001/* An aggregation of actors. 002 003 Copyright (c) 1997-2016 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 FIXME: things to review: 028 setDirector throws NameDuplicationException 029 preinitialize: validate attributes of this composite and 030 the attributes of its ports. 031 setDirector invalidatesSchedule of executiveDirector. 032 moved invalidation code from _addEntity to _finishedAddEntity 033 initialize now clears receivers.. This helps SampleDelay inside a modal models with reset transition work better. 034 */ 035package ptolemy.actor; 036 037import java.util.HashMap; 038import java.util.HashSet; 039import java.util.Iterator; 040import java.util.LinkedHashSet; 041import java.util.LinkedList; 042import java.util.List; 043import java.util.Map; 044import java.util.Set; 045import java.util.regex.Matcher; 046import java.util.regex.Pattern; 047 048import ptolemy.actor.parameters.ParameterPort; 049import ptolemy.actor.util.BooleanDependency; 050import ptolemy.actor.util.CausalityInterface; 051import ptolemy.actor.util.CausalityInterfaceForComposites; 052import ptolemy.actor.util.Dependency; 053import ptolemy.data.BooleanToken; 054import ptolemy.data.expr.Parameter; 055import ptolemy.kernel.ComponentEntity; 056import ptolemy.kernel.ComponentPort; 057import ptolemy.kernel.ComponentRelation; 058import ptolemy.kernel.CompositeEntity; 059import ptolemy.kernel.Entity; 060import ptolemy.kernel.InstantiableNamedObj; 061import ptolemy.kernel.Port; 062import ptolemy.kernel.util.ChangeRequest; 063import ptolemy.kernel.util.IllegalActionException; 064import ptolemy.kernel.util.InternalErrorException; 065import ptolemy.kernel.util.KernelRuntimeException; 066import ptolemy.kernel.util.NameDuplicationException; 067import ptolemy.kernel.util.Nameable; 068import ptolemy.kernel.util.NamedObj; 069import ptolemy.kernel.util.Workspace; 070import ptolemy.util.StringUtilities; 071 072/////////////////////////////////////////////////////////////////// 073//// CompositeActor 074 075/** 076 A CompositeActor is an aggregation of actors. It may have a 077 <i>local director</i>, which is an attribute of class Director that 078 is responsible for executing the contained actors. 079 At the top level of a hierarchy, a composite actor (the toplevel 080 CompositeActor of the topology) will normally exist with a local Director, 081 and no container. A composite actor at a lower level 082 of the hierarchy may also have a local director. A composite actor 083 with a local director is <i>opaque</i>, and serves the role of the 084 <i>wormhole</i> from Ptolemy Classic. Its ports are opaque, but it can 085 contain actors and relations. The toplevel composite actor is also 086 associated with a Manager object that is responsible for managing 087 any execution within the topology at a high level. 088 <p> 089 The <i>executive director</i> of a composite actor is the local director of 090 the actor's container. The toplevel composite actor has no executive 091 director, and getExecutiveDirector will return null. For transparent 092 composite actors, the executive director and the local director will be the 093 same. 094 <p> 095 The getDirector() method returns the local director if there is one. 096 Otherwise, it returns the <i>executive director</i> of the CompositeActor, 097 if there is one. Whatever it returns is called (simply) the 098 <i>director</i> of the composite (it may be local or executive). This 099 Director is responsible for the execution of all the actors contained 100 within the composite actor. 101 <p> 102 A composite actor must have an executive director in order to communicate with 103 the hierarchy around it. In fact, it cannot even receive data in its 104 input ports without an executive director, since the executive director 105 is responsible for supplying the receivers to the ports. 106 The toplevel composite actor has no executive director and cannot have 107 ports that transmit data, but it can still be executed as long as it has a 108 local director. If the getDirector() method returns null, then the 109 composite is not executable. 110 <p> 111 When a composite actor has both a director and an executive director, then 112 the model of computation implemented by the director need not be the 113 same as the model of computation implemented by the executive director. 114 This is the source of the hierarchical heterogeneity in Ptolemy II. 115 Multiple models of computation can be cleanly nested. 116 <p> 117 The ports of a CompositeActor are constrained to be IOPorts, the 118 relations to be IORelations, and the actors to be instances of 119 ComponentEntity that implement the Actor interface. Derived classes 120 may impose further constraints by overriding newPort(), _addPort(), 121 newRelation(), _addRelation(), and _addEntity(). 122 123 @author Mudit Goel, Edward A. Lee, Lukito Muliadi, Steve Neuendorffer, Contributor: Daniel Crawl, Bert Rodiers 124 @version $Id$ 125 @since Ptolemy II 0.2 126 @Pt.ProposedRating Green (cxh) 127 @Pt.AcceptedRating Yellow (neuendor) 128 @see ptolemy.actor.IOPort 129 @see ptolemy.actor.IORelation 130 @see ptolemy.kernel.ComponentEntity 131 @see ptolemy.actor.Director 132 @see ptolemy.actor.Manager 133 */ 134public class CompositeActor extends CompositeEntity 135 implements Actor, FiringsRecordable { 136 /** Construct a CompositeActor in the default workspace with no container 137 * and an empty string as its name. Add the actor to the workspace 138 * directory. 139 * You should set a director before attempting to execute it. 140 * You should set the container before sending data to it. 141 * Increment the version number of the workspace. 142 */ 143 public CompositeActor() { 144 super(); 145 _relationWidthInference = new RelationWidthInference(this); 146 } 147 148 /** Construct a CompositeActor in the specified workspace with no container 149 * and an empty string as a name. You can then change the name with 150 * setName(). If the workspace argument is null, then use the default 151 * workspace. 152 * You should set a director before attempting to execute it. 153 * You should set the container before sending data to it. 154 * Increment the version number of the workspace. 155 * @param workspace The workspace that will list the actor. 156 */ 157 public CompositeActor(Workspace workspace) { 158 super(workspace); 159 _relationWidthInference = new RelationWidthInference(this); 160 } 161 162 /** Create an actor with a name and a container. 163 * The container argument must not be null, or a 164 * NullPointerException will be thrown. This actor will use the 165 * workspace of the container for synchronization and version counts. 166 * If the name argument is null, then the name is set to the empty string. 167 * Increment the version of the workspace. 168 * This actor will have no 169 * local director initially, and its executive director will be simply 170 * the director of the container. 171 * You should set a director before attempting to execute it. 172 * 173 * @param container The container actor. 174 * @param name The name of this actor. 175 * @exception IllegalActionException If the container is incompatible 176 * with this actor. 177 * @exception NameDuplicationException If the name coincides with 178 * an actor already in the container. 179 */ 180 public CompositeActor(CompositeEntity container, String name) 181 throws IllegalActionException, NameDuplicationException { 182 super(container, name); 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// public methods //// 187 188 /** Append a listener to the current set of actor firing listeners. 189 * If the listener is already in the set, it will not be added again. 190 * Note that this method is basically the same as addDebugListener 191 * in the class NamedObj. 192 * @param listener The listener to which to send actor firing messages. 193 * @see #removeActorFiringListener(ActorFiringListener) 194 */ 195 @Override 196 public void addActorFiringListener(ActorFiringListener listener) { 197 // NOTE: This method needs to be synchronized to prevent two 198 // threads from each creating a new _actorFiringListeners list. 199 synchronized (this) { 200 if (_actorFiringListeners == null) { 201 _actorFiringListeners = new LinkedList<ActorFiringListener>(); 202 } 203 } 204 205 // NOTE: This has to be synchronized to prevent 206 // concurrent modification exceptions. 207 synchronized (_actorFiringListeners) { 208 if (_actorFiringListeners.contains(listener)) { 209 return; 210 } else { 211 _actorFiringListeners.add(listener); 212 } 213 214 _notifyingActorFiring = true; 215 } 216 } 217 218 /** Add the specified object to the set of objects whose 219 * preinitialize(), initialize(), and wrapup() 220 * methods should be invoked upon invocation of the corresponding 221 * methods of this object. 222 * @param initializable The object whose methods should be invoked. 223 * @see #removeInitializable(Initializable) 224 * @see #addPiggyback(Executable) 225 */ 226 @Override 227 public void addInitializable(Initializable initializable) { 228 if (_initializables == null) { 229 _initializables = new LinkedHashSet<Initializable>(); 230 } 231 _initializables.add(initializable); 232 } 233 234 /** Add the specified object to the set of objects whose action 235 * methods should be invoked upon invocation of the corresponding 236 * actions methods of this object. These methods will be invoked 237 * before the corresponding methods of this object. 238 * @param piggyback The piggyback object. 239 * @see #addInitializable(Initializable) 240 * @see #removePiggyback(Executable) 241 */ 242 public void addPiggyback(Executable piggyback) { 243 if (_piggybacks == null) { 244 _piggybacks = new LinkedHashSet<Executable>(); 245 } 246 _piggybacks.add(piggyback); 247 } 248 249 /** Clone the actor into the specified workspace. The new object is 250 * <i>not</i> added to the directory of that workspace (you must do this 251 * yourself if you want it there). 252 * The result is a composite actor with clones of the ports of the 253 * original actor, the contained actors, and the contained relations. 254 * The ports of the returned actor are not connected to anything. 255 * The connections of the relations are duplicated in the new composite, 256 * unless they cross levels, in which case an exception is thrown. 257 * The local director is cloned, if there is one. 258 * The executive director is not cloned. 259 * NOTE: This will not work if there are level-crossing transitions. 260 * 261 * @param workspace The workspace for the cloned object. 262 * @exception CloneNotSupportedException If the actor contains 263 * level crossing transitions so that its connections cannot be cloned, 264 * or if one of the attributes cannot be cloned. 265 * @return A new CompositeActor. 266 */ 267 @Override 268 public Object clone(Workspace workspace) throws CloneNotSupportedException { 269 // Some local variables are written to by constructors of contained 270 // actors. Those variables need to be set to null _before_ cloning 271 // so that the new instance gets its own version. 272 Set<Initializable> oldInitializables = _initializables; 273 _initializables = null; 274 Map<String, Set<IOPort>> oldPublishedPorts = _publishedPorts; 275 _publishedPorts = null; 276 Map<String, IORelation> oldPublisherRelations = _publisherRelations; 277 Director oldDirector = _director; 278 _director = null; 279 Set<Executable> oldPiggybacks = _piggybacks; 280 _piggybacks = null; 281 LinkedList<ActorFiringListener> oldActorFiringListeners = _actorFiringListeners; 282 _actorFiringListeners = null; 283 284 CompositeActor newObject = (CompositeActor) super.clone(workspace); 285 286 _initializables = oldInitializables; 287 _publishedPorts = oldPublishedPorts; 288 _publisherRelations = oldPublisherRelations; 289 _director = oldDirector; 290 _piggybacks = oldPiggybacks; 291 _actorFiringListeners = oldActorFiringListeners; 292 293 newObject._actorFiringListeners = null; 294 newObject._notifyingActorFiring = false; 295 newObject._causalityInterface = null; 296 newObject._derivedPiggybacks = null; 297 newObject._manager = null; 298 newObject._inputPortsVersion = -1; 299 newObject._outputPortsVersion = -1; 300 newObject._causalityInterfaceDirector = null; 301 newObject._receiversVersion = -1L; 302 // Don't set _relationWidthInference to null, see 7.1.5 in CompositeActor.tcl 303 //newObject._relationWidthInference = null; 304 newObject._relationWidthInference = new RelationWidthInference( 305 newObject); 306 return newObject; 307 } 308 309 /** Invalidate the schedule and type resolution and create 310 * new receivers if the specified port is an opaque 311 * output port. Also, notify the containers of any ports 312 * deeply connected on the inside by calling their connectionsChanged() 313 * methods, since their width may have changed. 314 * @param port The port that has connection changes. 315 */ 316 @Override 317 public void connectionsChanged(Port port) { 318 if (_debugging) { 319 _debug("Connections changed on port: " + port.getName()); 320 } 321 322 super.connectionsChanged(port); 323 324 if (port instanceof ComponentPort) { 325 // NOTE: deepInsidePortList() is not the right thing here 326 // since it will return the same port if it is opaque. 327 Iterator<?> insidePorts = ((ComponentPort) port).insidePortList() 328 .iterator(); 329 330 try { 331 _inConnectionsChanged = true; 332 333 while (insidePorts.hasNext()) { 334 ComponentPort insidePort = (ComponentPort) insidePorts 335 .next(); 336 Entity portContainer = (Entity) insidePort.getContainer(); 337 338 // Avoid an infinite loop where notifications are traded. 339 if (!(portContainer instanceof CompositeActor) 340 || !((CompositeActor) portContainer)._inConnectionsChanged) { 341 portContainer.connectionsChanged(insidePort); 342 } 343 } 344 } finally { 345 _inConnectionsChanged = false; 346 } 347 } 348 349 if (port instanceof IOPort) { 350 IOPort castPort = (IOPort) port; 351 352 if (castPort.isOpaque()) { 353 Manager manager = getManager(); 354 355 if (castPort.isOutput() && getDirector() != null 356 && manager != null && manager.getState() != Manager.IDLE 357 && manager.getState() != Manager.INFERING_WIDTHS 358 && manager.getState() != Manager.PREINITIALIZING) { 359 // Note that even if castPort is opaque, we still have to 360 // check for director above. 361 try { 362 castPort.createReceivers(); 363 } catch (IllegalActionException ex) { 364 // Should never happen. 365 throw new InternalErrorException(this, ex, 366 "Cannot create receivers"); 367 } 368 } 369 370 if (castPort.isInput() && getExecutiveDirector() != null 371 && manager != null && manager.getState() != Manager.IDLE 372 && manager.getState() != Manager.INFERING_WIDTHS 373 && manager.getState() != Manager.PREINITIALIZING) { 374 try { 375 castPort.createReceivers(); 376 } catch (IllegalActionException ex) { 377 // Should never happen. 378 throw new InternalErrorException(this, ex, 379 "Cannot create receivers"); 380 } 381 } 382 383 // Invalidate the local director schedule and types 384 if (getDirector() != null) { 385 getDirector().invalidateSchedule(); 386 getDirector().invalidateResolvedTypes(); 387 } 388 } 389 } 390 } 391 392 /** If this actor is opaque, transfer any data from the input ports 393 * of this composite to the ports connected on the inside, and then 394 * invoke the fire() method of its local director. 395 * The transfer is accomplished by calling the transferInputs() method 396 * of the local director (the exact behavior of which depends on the 397 * domain). If the actor is not opaque, throw an exception. 398 * This method is read-synchronized on the workspace, so the 399 * fire() method of the director need not be (assuming it is only 400 * called from here). After the fire() method of the director returns, 401 * send any output data created by calling the local director's 402 * transferOutputs method. 403 * 404 * @exception IllegalActionException If there is no director, or if 405 * the director's fire() method throws it, or if the actor is not 406 * opaque. 407 */ 408 @Override 409 public void fire() throws IllegalActionException { 410 if (_debugging) { 411 _debug("Calling fire()"); 412 } 413 414 try { 415 _workspace.getReadAccess(); 416 417 // First invoke piggybacked methods. 418 if (_piggybacks != null) { 419 // Invoke the fire() method of each piggyback. 420 for (Executable piggyback : _piggybacks) { 421 piggyback.fire(); 422 } 423 } 424 if (_derivedPiggybacks != null) { 425 // Invoke the fire() method of each piggyback. 426 for (Executable piggyback : _derivedPiggybacks) { 427 piggyback.fire(); 428 } 429 } 430 431 if (!isOpaque()) { 432 throw new IllegalActionException(this, 433 "Cannot fire a non-opaque actor."); 434 } 435 436 _transferPortParameterInputs(); 437 438 // Use the local director to transfer inputs from 439 // everything that is not a port parameter. 440 // The director will also update the schedule in 441 // the process, if necessary. 442 for (Iterator<?> inputPorts = inputPortList().iterator(); inputPorts 443 .hasNext() && !_stopRequested;) { 444 IOPort p = (IOPort) inputPorts.next(); 445 446 if (!(p instanceof ParameterPort)) { 447 _director.transferInputs(p); 448 } 449 } 450 451 if (_stopRequested) { 452 return; 453 } 454 455 _director.fire(); 456 457 if (_stopRequested) { 458 return; 459 } 460 461 // Use the local director to transfer outputs. 462 _director.transferOutputs(); 463 } finally { 464 _workspace.doneReading(); 465 } 466 467 if (_debugging) { 468 _debug("Called fire()"); 469 } 470 } 471 472 /** Create receivers for each port. If the port is an 473 * input port, then receivers are created for outside 474 * connections. If it is an output port, then receivers 475 * are created for inside connections. This method replaces 476 * any pre-existing receivers, so any data they contain 477 * will be lost. 478 * @exception IllegalActionException If any port throws it. 479 */ 480 @Override 481 public void createReceivers() throws IllegalActionException { 482 483 // NOTE: It really doesn't help to track the _receiversVersion 484 // here because if there is more than one composite actor 485 // in the model, then the workspace version will be changed 486 // when createReceivers() is called on the next one, so this 487 // one will think next time that the workspace has changed. 488 // This optimization needs to be done higher in the hierarchy. 489 if (workspace().getVersion() != _receiversVersion) { 490 List portList = new LinkedList(portList()); 491 Iterator<?> ports = portList.iterator(); 492 493 try { 494 workspace().getWriteAccess(); 495 while (ports.hasNext()) { 496 IOPort onePort = (IOPort) ports.next(); 497 onePort.createReceivers(); 498 } 499 _receiversVersion = workspace().getVersion(); 500 } finally { 501 // Note that this does not increment the workspace version. 502 // We have not changed the structure of the model. 503 workspace().doneTemporaryWriting(); 504 } 505 } 506 507 // Undid this change temporarily since the move of createReceivers breaks HDF 508 /* 509 for (Object actor : deepEntityList()) { 510 ((Actor) actor).createReceivers(); 511 } 512 */ 513 } 514 515 /** Create the schedule for this model, if necessary. 516 * @exception IllegalActionException If the schedule can't be created. 517 */ 518 public void createSchedule() throws IllegalActionException { 519 for (Object actor : deepEntityList()) { 520 if (actor instanceof CompositeActor) { 521 ((CompositeActor) actor).createSchedule(); 522 } 523 } 524 getDirector().createSchedule(); 525 } 526 527 /** Return a causality interface for this actor. This returns an 528 * instance of {@link CausalityInterfaceForComposites}. 529 * If this is called multiple times, the same object is returned each 530 * time unless the director has changed since the last call, in 531 * which case a new object is returned. 532 * @return A representation of the dependencies between input ports 533 * and output ports. 534 */ 535 @Override 536 public CausalityInterface getCausalityInterface() { 537 // FIXME: Although this director may not have changed, a director 538 // higher in the hierarchy may have changed. The base class Director 539 // delegates up the hierarchy to decide what kind of Dependency to use, 540 // so if a director higher in the hierarchy has changed, then we really 541 // need to recreate the causality interface. 542 // However, it doesn't seem to work to use the workspace version to 543 // replace the causality interface! The reason seems to be that 544 // if we do that, the causality interface gets recreated _after_ 545 // actors have had preinitialize() called, which is when they prune 546 // their input/output dependencies. 547 Director director = getDirector(); 548 if (_causalityInterface != null 549 && _causalityInterfaceDirector == director) { 550 return _causalityInterface; 551 } 552 if (director != null) { 553 _causalityInterface = director.getCausalityInterface(); 554 _causalityInterfaceDirector = director; 555 return _causalityInterface; 556 } 557 Dependency defaultDependency = BooleanDependency.OTIMES_IDENTITY; 558 _causalityInterface = new CausalityInterfaceForComposites(this, 559 defaultDependency); 560 _causalityInterfaceDirector = null; 561 return _causalityInterface; 562 } 563 564 /** Return the director responsible for execution of the contained 565 * actors. This will be either the local director (if it exists) or the 566 * executive director (obtained using getExecutiveDirector()). 567 * This method is read-synchronized on the workspace. 568 * 569 * @return The director responsible for invocation of inside actors. 570 * @see #setDirector(Director) 571 */ 572 @Override 573 public Director getDirector() { 574 try { 575 _workspace.getReadAccess(); 576 577 if (_director != null) { 578 return _director; 579 } 580 // NOTE: It is slightly more efficient to 581 // call this directly, rather than using 582 // getExecutiveDirector(), and this gets 583 // called alot. 584 // NOTE: Cast should be safe because this 585 // has to be contained by an actor to be run. 586 Nameable container = getContainer(); 587 if (container instanceof Actor) { 588 return ((Actor) container).getDirector(); 589 } 590 return null; 591 } finally { 592 _workspace.doneReading(); 593 } 594 } 595 596 /** Return the executive director of this CompositeActor. 597 * The container (if any) is queried for its (local) director. 598 * If it has none, or there 599 * is no container, then return null. This method is read-synchronized 600 * on the workspace. 601 * 602 * @return The executive director of this composite actor. 603 */ 604 @Override 605 public Director getExecutiveDirector() { 606 try { 607 _workspace.getReadAccess(); 608 609 Nameable container = getContainer(); 610 611 if (container instanceof Actor) { 612 return ((Actor) container).getDirector(); 613 } 614 615 return null; 616 } finally { 617 _workspace.doneReading(); 618 } 619 } 620 621 /** Get the manager responsible for execution of this composite actor. 622 * If this is the toplevel composite actor, then return what was 623 * set with setManager(). 624 * For others, recursively call on the container, until the 625 * toplevel composite actor is reached. 626 * This method is read-synchronized on the workspace. 627 * @see #setManager(Manager) 628 * 629 * @return The Manager of the topology that contains the composite actor. 630 */ 631 @Override 632 public Manager getManager() { 633 try { 634 _workspace.getReadAccess(); 635 636 if (_manager != null) { 637 return _manager; 638 } 639 640 Nameable container = getContainer(); 641 642 if (container instanceof Actor) { 643 return ((Actor) container).getManager(); 644 } 645 646 return null; 647 } finally { 648 _workspace.doneReading(); 649 } 650 } 651 652 /** Get the published port with named name. 653 * @param name The name of the published port. 654 * @return The port of the publisher that has named name. 655 * @exception IllegalActionException If the publisher can't be found. 656 * @exception NameDuplicationException If there are multiple 657 * publishers with the same name. 658 */ 659 final public IOPort getPublishedPort(String name) 660 throws IllegalActionException, NameDuplicationException { 661 NamedObj container = getContainer(); 662 if (!isOpaque() && container instanceof CompositeActor 663 && !((CompositeActor) container).isClassDefinition()) { 664 return ((CompositeActor) container).getPublishedPort(name); 665 } else { 666 if (_publishedPorts == null) { 667 throw new IllegalActionException(this, 668 "Can't find the publisher for \"" + name + "\"."); 669 } 670 671 Set<IOPort> publishedPorts = _publishedPorts.get(name); 672 if (publishedPorts == null || publishedPorts.size() == 0) { 673 StringBuffer message = new StringBuffer(); 674 for (String keyName : _publishedPorts.keySet()) { 675 message.append(keyName + " "); 676 } 677 throw new IllegalActionException(this, 678 "Can't find the publisher for \"" + name 679 + "\"., names were: " + message); 680 } else if (publishedPorts.size() > 1) { 681 // Check to see if any of the publishedPorts are within a ClassDefinition. 682 // FIXME: we should be able to do this before now, but when ports are being 683 // registered, the container of the CompositeActor is often null, so we 684 // can't tell if a port is in a ClassDefinition. 685 // Test: $PTII/ptolemy/actor/lib/test/auto/PublisherPortSubscriberChannelVariablesAOC2.xml 686 StringBuffer message = new StringBuffer(); 687 Iterator ports = publishedPorts.iterator(); 688 while (ports.hasNext()) { 689 IOPort port = (IOPort) ports.next(); 690 InstantiableNamedObj actor = (InstantiableNamedObj) port 691 .getContainer(); 692 if (actor != null && actor.isWithinClassDefinition()) { 693 ports.remove(); 694 } else { 695 if (port instanceof PubSubPort) { 696 PubSubPort pubSubPort = (PubSubPort) port; 697 message.append(" port: " + pubSubPort + "name: " 698 + pubSubPort.getName() + " channel: " 699 + pubSubPort.channel + "\n"); 700 } 701 } 702 } 703 if (publishedPorts.size() != 1) { 704 throw new NameDuplicationException(this, 705 "We have " + publishedPorts.size() 706 + " ports with the name \"" + name 707 + "\", which is not equal to 1.\n" 708 + message); 709 } 710 } 711 712 Iterator<IOPort> iterator = publishedPorts.iterator(); 713 return iterator.next(); 714 } 715 } 716 717 /** Get the published ports with names that match a regular expression. 718 * @param pattern The regular expression pattern to match. 719 * @return The ports of the publisher that match the regular expression. 720 * @exception IllegalActionException If the publisher can't be found. 721 * @exception NameDuplicationException If there are multiple 722 * publishers with the same name. 723 */ 724 final public List<IOPort> getPublishedPorts(Pattern pattern) 725 throws IllegalActionException, NameDuplicationException { 726 List<IOPort> ports = new LinkedList<IOPort>(); 727 NamedObj container = getContainer(); 728 if (!isOpaque() && container instanceof CompositeActor 729 && !((CompositeActor) container).isClassDefinition()) { 730 return ((CompositeActor) container).getPublishedPorts(pattern); 731 } else { 732 if (_publishedPorts != null) { 733 734 // FindBugs: ptolemy.actor.CompositeActor.getPublishedPorts(Pattern) makes inefficient use of keySet iterator instead of entrySet iterator 735 //for (String name : _publishedPorts.keySet()) { 736 for (Map.Entry<String, Set<IOPort>> entry : _publishedPorts 737 .entrySet()) { 738 //Matcher matcher = pattern.matcher(name); 739 Matcher matcher = pattern.matcher(entry.getKey()); 740 if (matcher.matches()) { 741 //ports.addAll(_publishedPorts.get(name)); 742 ports.addAll(entry.getValue()); 743 } 744 } 745 } 746 } 747 748 return ports; 749 } 750 751 /** Get the channel name of a published port. 752 * @param port The published port. 753 * @return The name of the channel of the published port. 754 */ 755 756 public String getPublishedPortChannel(IOPort port) { 757 NamedObj container = getContainer(); 758 if (!isOpaque() && container instanceof CompositeActor 759 && !((CompositeActor) container).isClassDefinition()) { 760 return ((CompositeActor) container).getPublishedPortChannel(port); 761 } else { 762 if (_publishedPorts != null) { 763 // FindBugs: ptolemy.actor.CompositeActor.getPublishedPortChannel(IOPort) makes inefficient use of keySet iterator instead of entrySet iterator 764 765 //for (String name : _publishedPorts.keySet()) { 766 // if (_publishedPorts.get(name).contains(port)) { 767 768 for (Map.Entry<String, Set<IOPort>> entry : _publishedPorts 769 .entrySet()) { 770 if (entry.getValue().contains(port)) { 771 return entry.getKey(); 772 } 773 } 774 } 775 } 776 777 return ""; 778 } 779 780 /** Get the name of the channel that the port subscribes to. 781 * @param port The subscribed port. 782 * @return The name of the channel. 783 */ 784 785 public String getSubscribedPortChannel(IOPort port) { 786 NamedObj container = getContainer(); 787 if (!isOpaque() && container instanceof CompositeActor 788 && !((CompositeActor) container).isClassDefinition()) { 789 return ((CompositeActor) container).getPublishedPortChannel(port); 790 } else { 791 if (_subscribedPorts != null) { 792 // FindBugs: ptolemy.actor.CompositeActor.getSubscribedPortChannel(IOPort) makes inefficient use of keySet iterator instead of entrySet iterator 793 // for (String name : _subscribedPorts.keySet()) { 794 for (Map.Entry<String, List<IOPort>> entry : _subscribedPorts 795 .entrySet()) { 796 //if (_subscribedPorts.get(name).contains(port)) { 797 // return name; 798 if (entry.getValue().contains(port)) { 799 return entry.getKey(); 800 } 801 } 802 } 803 } 804 805 return ""; 806 } 807 808 /** Determine whether widths are currently being inferred or not. 809 * @return True When widths are currently being inferred. 810 */ 811 public boolean inferringWidths() { 812 RelationWidthInference widthInferenceAlgorithm = _getWidthInferenceAlgorithm(); 813 if (widthInferenceAlgorithm != null) { 814 return widthInferenceAlgorithm.inferringWidths(); 815 } else { 816 return false; 817 } 818 } 819 820 /** 821 * Infer the width of the relations for which no width has been 822 * specified yet. 823 * The specified actor must be the top level container of the model. 824 * @exception IllegalActionException If the widths of the 825 * relations at port are not consistent or if the width cannot be 826 * inferred for a relation. 827 */ 828 public void inferWidths() throws IllegalActionException { 829 RelationWidthInference relationWidthInference = _getWidthInferenceAlgorithm(); 830 relationWidthInference.inferWidths(); 831 } 832 833 /** Initialize this actor. If this actor is opaque, invoke the 834 * initialize() method of its local director. Otherwise, throw an 835 * exception. This method is read-synchronized on the workspace, 836 * so the initialize() method of the director need not be 837 * (assuming it is only called from here). 838 * 839 * @exception IllegalActionException If there is no director, or 840 * if the director's initialize() method throws it, or if the 841 * actor is not opaque. 842 */ 843 @Override 844 public void initialize() throws IllegalActionException { 845 if (_debugging) { 846 _debug("Called initialize()"); 847 } 848 849 try { 850 _workspace.getReadAccess(); 851 852 if (!isOpaque()) { 853 throw new IllegalActionException(this, 854 "Cannot initialize a non-opaque actor."); 855 } 856 857 // Clear all of the contained actor's input ports. 858 for (Iterator<?> actors = deepEntityList().iterator(); actors 859 .hasNext();) { 860 Entity actor = (Entity) actors.next(); 861 Iterator<?> ports = actor.portList().iterator(); 862 863 while (ports.hasNext()) { 864 IOPort port = (IOPort) ports.next(); 865 866 // if port has default value reset the saved persistent value. 867 port.reset(); 868 869 if (port.isInput()) { 870 // Reset all receivers. 871 Receiver[][] receivers = port.getReceivers(); 872 873 if (receivers == null) { 874 throw new InternalErrorException(this, null, 875 "port.getReceivers() returned null! " 876 + "This should never happen. " 877 + "port was '" + port + "'"); 878 } 879 880 for (Receiver[] receivers2 : receivers) { 881 for (Receiver element : receivers2) { 882 element.reset(); 883 } 884 } 885 } 886 } 887 } 888 889 // Clear all of the output ports. 890 Iterator<?> ports = portList().iterator(); 891 892 while (ports.hasNext()) { 893 IOPort port = (IOPort) ports.next(); 894 895 if (port.isOutput()) { 896 // Clear all insideReceivers. 897 Receiver[][] receivers = port.getInsideReceivers(); 898 899 for (Receiver[] receivers2 : receivers) { 900 for (Receiver element : receivers2) { 901 element.reset(); 902 } 903 } 904 } 905 } 906 907 // Next invoke initializable methods. 908 // This should be done _after_ clearing the receivers above 909 // because an initializable or piggyback may produce outputs. 910 if (_initializables != null) { 911 for (Initializable initializable : _initializables) { 912 initializable.initialize(); 913 } 914 } 915 916 // Next invoke piggybacked methods. 917 if (_piggybacks != null) { 918 // Invoke the initialize() method of each piggyback. 919 for (Executable piggyback : _piggybacks) { 920 piggyback.initialize(); 921 } 922 } 923 if (_derivedPiggybacks != null) { 924 // Invoke the initialize() method of each piggyback. 925 for (Executable piggyback : _derivedPiggybacks) { 926 piggyback.initialize(); 927 } 928 } 929 930 // Note that this is assured of firing the local director, 931 // not the executive director, because this is opaque. 932 // The initialize() method of the local director must be called 933 // after the ports are cleared, because the FixedPointDirector 934 // relies on this to reset the status of its receivers. 935 getDirector().initialize(); 936 } finally { 937 _workspace.doneReading(); 938 } 939 } 940 941 /** List the input ports of this actor. 942 * Note that this method returns the ports directly 943 * contained by this actor, whether they are transparent or not. 944 * This method is read-synchronized on the workspace. 945 * @return A list of IOPort objects. 946 */ 947 @Override 948 public List inputPortList() { 949 try { 950 _workspace.getReadAccess(); 951 952 if (_inputPortsVersion != _workspace.getVersion()) { 953 // Update the cache. 954 List<IOPort> inputPorts = new LinkedList<IOPort>(); 955 Iterator<?> ports = portList().iterator(); 956 957 while (ports.hasNext()) { 958 IOPort p = (IOPort) ports.next(); 959 960 if (p.isInput()) { 961 inputPorts.add(p); 962 } 963 } 964 965 _cachedInputPorts = inputPorts; 966 _inputPortsVersion = _workspace.getVersion(); 967 } 968 969 return _cachedInputPorts; 970 } finally { 971 _workspace.doneReading(); 972 } 973 } 974 975 /** If this actor is opaque, invoke the isFireFunctional() method 976 * of the local director and return its result. Otherwise, return true. 977 * Normally this method will not be invoked on a non-opaque 978 * composite actor. 979 * 980 * @return True if the local director's isFireFunctional() method 981 * returns true or if this actor is not opaque. 982 */ 983 @Override 984 public boolean isFireFunctional() { 985 if (isOpaque()) { 986 // If any piggybacked object is not functional, then this object 987 // is not functional. 988 if (_piggybacks != null) { 989 // Invoke the isFireFunctional() method of each piggyback. 990 for (Executable piggyback : _piggybacks) { 991 if (!piggyback.isFireFunctional()) { 992 return false; 993 } 994 } 995 } 996 if (_derivedPiggybacks != null) { 997 // Invoke the isFireFunctional() method of each piggyback. 998 for (Executable piggyback : _derivedPiggybacks) { 999 if (!piggyback.isFireFunctional()) { 1000 return false; 1001 } 1002 } 1003 } 1004 return getDirector().isFireFunctional(); 1005 } else { 1006 return true; 1007 } 1008 } 1009 1010 /** Return true if this actor contains a local director. 1011 * Otherwise, return false. This method is <i>not</i> 1012 * synchronized on the workspace, so the caller should be. 1013 */ 1014 @Override 1015 public boolean isOpaque() { 1016 return _director != null; 1017 } 1018 1019 /** Return true if a port is in the published port list 1020 * at this level. 1021 * @param port The port to be checked against the list of published ports. 1022 * @return True if the port was added with 1023 * {@link #registerPublisherPort(String, IOPort, boolean)}. 1024 */ 1025 public boolean isPublishedPort(IOPort port) { 1026 if (_publishedPorts != null) { 1027 for (Set<IOPort> ports : _publishedPorts.values()) { 1028 if (ports.contains(port)) { 1029 return true; 1030 } 1031 } 1032 } 1033 1034 return false; 1035 } 1036 1037 /** Return false if all input ports have non-empty default values, 1038 * or if this actor is opaque and the contained director indicates 1039 * that it is non-strict. 1040 * Normally this method will not be invoked on a non-opaque 1041 * composite actor. 1042 * Note that ParameterPort is not treated as having a default value 1043 * because such ports might be used in a context where it is important 1044 * to supply them with an input value. 1045 * @return False if this actor does not need to be provided with 1046 * inputs to fire. 1047 * @exception IllegalActionException Thrown if causality interface 1048 * cannot be computed, or if the defaultValue expression cannot be 1049 * evaluated on an input port. 1050 */ 1051 @Override 1052 public boolean isStrict() throws IllegalActionException { 1053 List<IOPort> ports = inputPortList(); 1054 boolean foundAnInputPort = false; 1055 for (IOPort port : ports) { 1056 foundAnInputPort = true; 1057 if (port.defaultValue.getToken() == null) { 1058 // Found an input port with no default value. 1059 if (isOpaque()) { 1060 return getDirector().isStrict(); 1061 } else { 1062 return true; 1063 } 1064 } 1065 } 1066 // Get to here if either all input ports have a default value 1067 // or there are no input ports. 1068 if (isOpaque() && foundAnInputPort) { 1069 return getDirector().isStrict(); 1070 } else { 1071 return true; 1072 } 1073 } 1074 1075 /** Invoke a specified number of iterations of the actor. An 1076 * iteration is equivalent to invoking prefire(), fire(), and 1077 * postfire(), in that order. In an iteration, if prefire() 1078 * returns true, then fire() will be called once, followed by 1079 * postfire(). Otherwise, if prefire() returns false, fire() 1080 * and postfire() are not invoked, and this method returns 1081 * NOT_READY. If postfire() returns false, then no more 1082 * iterations are invoked, and this method returns STOP_ITERATING. 1083 * Otherwise, it returns COMPLETED. If stop() is called during 1084 * this iteration, then cease iterating and return STOP_ITERATING. 1085 * <p> 1086 * This base class method actually invokes prefire(), fire(), 1087 * and postfire(), as described above, but a derived class 1088 * may override the method to execute more efficient code. 1089 * 1090 * @param count The number of iterations to perform. 1091 * @return NOT_READY, STOP_ITERATING, or COMPLETED. 1092 * @exception IllegalActionException If iterating is not 1093 * permitted, or if prefire(), fire(), or postfire() throw it. 1094 */ 1095 @Override 1096 public int iterate(int count) throws IllegalActionException { 1097 if (_debugging) { 1098 _debug("Called iterate(" + count + ")"); 1099 } 1100 1101 // First invoke piggybacked methods. 1102 // If any piggybacked object returns NOT_READY, 1103 // then we stop there and return NOT_READY. 1104 // If any returns STOP_ITERATING, then we 1105 // continue through to the completion of this 1106 // iteration, but then return STOP_ITERATING. 1107 boolean stopIterating = false; 1108 if (_piggybacks != null) { 1109 // Invoke the iterate() method of each piggyback. 1110 for (Executable piggyback : _piggybacks) { 1111 int result = piggyback.iterate(count); 1112 if (result == NOT_READY) { 1113 return NOT_READY; 1114 } else if (result == STOP_ITERATING) { 1115 stopIterating = true; 1116 } 1117 } 1118 } 1119 if (_derivedPiggybacks != null) { 1120 // Invoke the iterate() method of each piggyback. 1121 for (Executable piggyback : _derivedPiggybacks) { 1122 int result = piggyback.iterate(count); 1123 if (result == NOT_READY) { 1124 return NOT_READY; 1125 } else if (result == STOP_ITERATING) { 1126 stopIterating = true; 1127 } 1128 } 1129 } 1130 1131 int n = 0; 1132 1133 while (n++ < count && !_stopRequested) { 1134 1135 if (_notifyingActorFiring) { 1136 _actorFiring(FiringEvent.BEFORE_PREFIRE, n); 1137 } 1138 1139 if (prefire()) { 1140 1141 if (_notifyingActorFiring) { 1142 _actorFiring(FiringEvent.AFTER_PREFIRE, n); 1143 _actorFiring(FiringEvent.BEFORE_FIRE, n); 1144 } 1145 1146 fire(); 1147 1148 if (_notifyingActorFiring) { 1149 _actorFiring(FiringEvent.AFTER_FIRE, n); 1150 _actorFiring(FiringEvent.BEFORE_POSTFIRE, n); 1151 } 1152 1153 boolean pfire = postfire(); 1154 1155 if (_notifyingActorFiring) { 1156 _actorFiring(FiringEvent.AFTER_POSTFIRE, n); 1157 } 1158 1159 if (!pfire) { 1160 return Executable.STOP_ITERATING; 1161 } 1162 } else { 1163 1164 if (_notifyingActorFiring) { 1165 _actorFiring(FiringEvent.AFTER_PREFIRE, n); 1166 } 1167 return Executable.NOT_READY; 1168 } 1169 } 1170 1171 if (_stopRequested || stopIterating) { 1172 return Executable.STOP_ITERATING; 1173 } else { 1174 return Executable.COMPLETED; 1175 } 1176 } 1177 1178 /** Link the subscriberPort with a already registered "published port" coming 1179 * from a publisher. The name is the name being used in the 1180 * matching process to match publisher and subscriber. A 1181 * subscriber interested in the output of this publisher uses 1182 * the name. This registration process of publisher 1183 * typically happens before the model is preinitialized, 1184 * for example when opening the model. The subscribers 1185 * will look for publishers during the preinitialization phase. 1186 * @param name The name is being used in the matching process 1187 * to match publisher and subscriber. 1188 * @param subscriberPort The subscribed port. 1189 * @return The publisher port. 1190 * @exception NameDuplicationException If there are name conflicts 1191 * as a result of the added relations or ports. 1192 * @exception IllegalActionException If the published port cannot be found. 1193 */ 1194 public IOPort linkToPublishedPort(String name, IOPort subscriberPort) 1195 throws IllegalActionException, NameDuplicationException { 1196 NamedObj container = getContainer(); 1197 if (!isOpaque() && container instanceof CompositeActor 1198 && !((CompositeActor) container).isClassDefinition()) { 1199 // Published ports are not propagated if this actor 1200 // is opaque. 1201 return ((CompositeActor) container).linkToPublishedPort(name, 1202 subscriberPort); 1203 } else { 1204 IOPort publishedPort = getPublishedPort(name); 1205 IORelation relation = _publisherRelations != null 1206 ? _publisherRelations.get(name) 1207 : null; 1208 if (relation == null) { 1209 try { 1210 // CompositeActor always creates an IORelation. 1211 relation = (IORelation) newRelation( 1212 uniqueName("publisherRelation")); 1213 } catch (NameDuplicationException e) { 1214 // Shouldn't happen. 1215 throw new IllegalStateException(e); 1216 } 1217 // Prevent the relation and its links from being exported. 1218 relation.setPersistent(false); 1219 // Prevent the relation from showing up in vergil. 1220 new Parameter(relation, "_hide", BooleanToken.TRUE); 1221 publishedPort.liberalLink(relation); 1222 if (_publisherRelations == null) { 1223 _publisherRelations = new HashMap<String, IORelation>(); 1224 } 1225 _publisherRelations.put(name, relation); 1226 } 1227 if (!subscriberPort.isLinked(relation)) { 1228 subscriberPort.liberalLink(relation); 1229 notifyConnectivityChange(); 1230 1231 Director director = getDirector(); 1232 if (director != null) { 1233 director.invalidateSchedule(); 1234 director.invalidateResolvedTypes(); 1235 } 1236 } 1237 return publishedPort; 1238 } 1239 } 1240 1241 /** Link the subscriberPort with an already registered "published port" coming 1242 * from a publisher. The name gives the channel that 1243 * matches the publisher and subscriber. 1244 * The publisher is registered before the model is preinitialized, 1245 * when its channel parameter is set. 1246 * The subscribers call this method 1247 * to look for publishers during the preinitialization phase. 1248 * @param name The name being used in the matching process 1249 * to match publisher and subscriber. 1250 * @param subscriberPort The subscriber port. 1251 * @param global Specification of whether the data is subscribed 1252 * globally. If set to true, then subscribers will see values 1253 * published by publishers anywhere in the model that reference 1254 * the same channel by name. If set to false, then only values 1255 * published by publishers that are fired by the same director 1256 * are seen by this subscriber. 1257 * @return The publisher port. 1258 * @exception NameDuplicationException If there are name conflicts 1259 * as a result of the added relations or ports. 1260 * @exception IllegalActionException If the published port cannot be found. 1261 */ 1262 public IOPort linkToPublishedPort(String name, IOPort subscriberPort, 1263 boolean global) 1264 throws IllegalActionException, NameDuplicationException { 1265 NamedObj container = getContainer(); 1266 if (!isOpaque() && container instanceof CompositeActor 1267 && !((CompositeActor) container).isClassDefinition()) { 1268 // Published ports are not propagated if this actor 1269 // is opaque. 1270 return ((CompositeActor) container).linkToPublishedPort(name, 1271 subscriberPort, global); 1272 } else { 1273 try { 1274 return linkToPublishedPort(name, subscriberPort); 1275 } catch (IllegalActionException e) { 1276 if (!global || !(container instanceof CompositeActor)) { 1277 throw e; 1278 } else { 1279 if (_debugging) { 1280 _debug("Failed to find publisher for channel \"" + name 1281 + "\" in " + getFullName() 1282 + ". Trying up the hierarchy."); 1283 } 1284 1285 String portName = "_subscriber_" 1286 + StringUtilities.sanitizeName(name); 1287 IOPort port = (IOPort) getPort(portName); 1288 if (port == null) { 1289 port = (IOPort) newPort(portName); 1290 new Parameter(port, "_hide", BooleanToken.TRUE); 1291 // Also make sure the port does not show up on the inside. 1292 new Parameter(port, "_hideInside", BooleanToken.TRUE); 1293 port.setPersistent(false); 1294 port.setInput(true); 1295 port.setMultiport(true); 1296 port.setDefaultWidth(0); 1297 1298 IORelation relation = null; 1299 //connect the newly created port to the subscriber port 1300 try { 1301 // CompositeActor always creates an IORelation. 1302 relation = (IORelation) newRelation(uniqueName( 1303 subscriberPort.getContainer().getName() 1304 + "subscriberExternalRelationB")); 1305 } catch (NameDuplicationException ex) { 1306 // Shouldn't happen. 1307 throw new IllegalStateException(ex); 1308 } 1309 // Prevent the relation and its links from being exported. 1310 relation.setPersistent(false); 1311 // Prevent the relation from showing up in vergil. 1312 new Parameter(relation, "_hide", BooleanToken.TRUE); 1313 port.liberalLink(relation); 1314 1315 if (!subscriberPort.isLinked(relation)) { 1316 subscriberPort.liberalLink(relation); 1317 } 1318 notifyConnectivityChange(); 1319 } 1320 1321 return ((CompositeActor) container) 1322 .linkToPublishedPort(name, port, global); 1323 } 1324 } 1325 } 1326 } 1327 1328 /** Link the subscriberPort with a already registered "published port" coming 1329 * from a publisher. The pattern represents the name being used in the 1330 * matching process to match publisher and subscriber. A 1331 * subscriber interested in the output of this publisher uses 1332 * the name. This registration process of publisher 1333 * typically happens before the model is preinitialized, 1334 * for example when opening the model. The subscribers 1335 * will look for publishers during the preinitialization phase. 1336 * @param pattern The pattern is being used in the matching process 1337 * to match publisher and subscriber. 1338 * @param subscriberPort The subscribed port. 1339 * @exception NameDuplicationException If there are name conflicts 1340 * as a result of the added relations or ports. 1341 * @exception IllegalActionException If the published port cannot be found. 1342 */ 1343 public void linkToPublishedPort(Pattern pattern, TypedIOPort subscriberPort) 1344 throws IllegalActionException, NameDuplicationException { 1345 NamedObj container = getContainer(); 1346 if (!isOpaque() && container instanceof CompositeActor 1347 && !((CompositeActor) container).isClassDefinition()) { 1348 // Published ports are not propagated if this actor 1349 // is opaque. 1350 ((CompositeActor) container).linkToPublishedPort(pattern, 1351 subscriberPort); 1352 } else { 1353 if (_publishedPorts != null) { 1354 boolean matched = false; 1355 for (String name : _publishedPorts.keySet()) { 1356 Matcher matcher = pattern.matcher(name); 1357 //System.out.println("Match " + name); 1358 if (matcher.matches()) { 1359 matched = true; 1360 linkToPublishedPort(name, subscriberPort); 1361 } 1362 } 1363 if (!matched) { 1364 throw new IllegalActionException(this, 1365 "Failed to find a publisher to match \"" + pattern 1366 + "\""); 1367 } 1368 } else { 1369 throw new IllegalActionException(this, 1370 "No Publishers were found adjacent to or " + "below " 1371 + subscriberPort.getContainer().getFullName()); 1372 } 1373 } 1374 } 1375 1376 /** Link the subscriberPort with a already registered "published port" coming 1377 * from a publisher. The pattern represents the name being used in the 1378 * matching process to match publisher and subscriber. A 1379 * subscriber interested in the output of this publisher uses 1380 * the name. This registration process of publisher 1381 * typically happens before the model is preinitialized, 1382 * for example when opening the model. The subscribers 1383 * will look for publishers during the preinitialization phase. 1384 * @param pattern The pattern is being used in the matching process 1385 * to match publisher and subscriber. 1386 * @param subscriberPort The subscribed port. 1387 * @param global Specification of whether the data is subscribed 1388 * globally. If set to true, then subscribers will see values 1389 * published by publishers anywhere in the model that reference 1390 * the same channel by name. If set to false, then only values 1391 * published by publishers that are fired by the same director 1392 * are seen by this subscriber. 1393 * @exception NameDuplicationException If there are name conflicts 1394 * as a result of the added relations or ports. 1395 * @exception IllegalActionException If the published port cannot be found. 1396 */ 1397 public void linkToPublishedPort(Pattern pattern, TypedIOPort subscriberPort, 1398 boolean global) 1399 throws IllegalActionException, NameDuplicationException { 1400 NamedObj container = getContainer(); 1401 if (!isOpaque() && container instanceof CompositeActor 1402 && !((CompositeActor) container).isClassDefinition()) { 1403 // Published ports are not propagated if this actor 1404 // is opaque. 1405 ((CompositeActor) container).linkToPublishedPort(pattern, 1406 subscriberPort, global); 1407 } else { 1408 if (_publishedPorts == null) { 1409 if (!global || this == toplevel()) { 1410 throw new IllegalActionException( 1411 subscriberPort.getContainer(), 1412 "No Publishers were found adjacent to or below " 1413 + subscriberPort.getContainer() 1414 .getFullName()); 1415 } 1416 } else { 1417 boolean matched = false; 1418 for (String name : _publishedPorts.keySet()) { 1419 Matcher matcher = pattern.matcher(name); 1420 //System.out.println("Match " + name); 1421 if (matcher.matches()) { 1422 matched = true; 1423 linkToPublishedPort(name, subscriberPort); 1424 } 1425 } 1426 if (!matched && (!global || this == toplevel())) { 1427 throw new IllegalActionException( 1428 subscriberPort.getContainer(), 1429 "Failed to find a publisher to match \"" + pattern 1430 + "\""); 1431 } 1432 } 1433 if (global && this != toplevel()) { 1434 String portName = "_subscriber_" 1435 + StringUtilities.sanitizeName(pattern.toString()); 1436 IOPort port = (IOPort) getPort(portName); 1437 if (port == null) { 1438 port = (IOPort) newPort(portName); 1439 new Parameter(port, "_hide", BooleanToken.TRUE); 1440 // Also make sure the port does not show up on the inside. 1441 new Parameter(port, "_hideInside", BooleanToken.TRUE); 1442 port.setPersistent(false); 1443 port.setInput(true); 1444 port.setMultiport(true); 1445 port.setDefaultWidth(0); 1446 } 1447 1448 if (!subscriberPort.connectedPortList().contains(port)) { 1449 IORelation relation = null; 1450 //connect the newly created port to the subscriber port 1451 try { 1452 // CompositeActor always creates an IORelation. 1453 relation = (IORelation) newRelation(uniqueName( 1454 subscriberPort.getContainer().getName() 1455 + "subscriberExternalRelationA")); 1456 } catch (NameDuplicationException e) { 1457 // Shouldn't happen. 1458 throw new IllegalStateException(e); 1459 } 1460 // Prevent the relation and its links from being exported. 1461 relation.setPersistent(false); 1462 // Prevent the relation from showing up in vergil. 1463 new Parameter(relation, "_hide", BooleanToken.TRUE); 1464 1465 port.liberalLink(relation); 1466 1467 if (!subscriberPort.isLinked(relation)) { 1468 subscriberPort.liberalLink(relation); 1469 notifyConnectivityChange(); 1470 } 1471 1472 } 1473 1474 if (container instanceof CompositeActor) { 1475 ((CompositeActor) container).linkToPublishedPort(pattern, 1476 (TypedIOPort) port, global); 1477 } 1478 } 1479 } 1480 } 1481 1482 /** 1483 * Return whether the current widths of the relation in the model 1484 * are no longer valid anymore and the widths need to be inferred again. 1485 * @return True when width inference needs to be executed again. 1486 * @exception KernelRuntimeException If toplevel not a CompositeActor. 1487 */ 1488 public boolean needsWidthInference() throws KernelRuntimeException { 1489 return _getWidthInferenceAlgorithm().needsWidthInference(); 1490 } 1491 1492 /** Notify the manager that the connectivity in the model changed 1493 * (width of relation changed, relations added, linked to different ports, ...). 1494 * This will invalidate the current width inference. 1495 */ 1496 public void notifyConnectivityChange() { 1497 try { 1498 RelationWidthInference widthInferenceAlgorithm = _getWidthInferenceAlgorithm(); 1499 if (widthInferenceAlgorithm != null) { 1500 widthInferenceAlgorithm.notifyConnectivityChange(); 1501 } 1502 } catch (KernelRuntimeException ex) { 1503 // Exception is not relevant when reporting changes. 1504 } 1505 } 1506 1507 /** Return a new receiver of a type compatible with the local director. 1508 * Derived classes may further specialize this to return a receiver 1509 * specialized to the particular actor. This method is <i>not</i> 1510 * synchronized on the workspace, so the caller should be. 1511 * 1512 * @exception IllegalActionException If there is no local director. 1513 * @return A new object implementing the Receiver interface. 1514 */ 1515 public Receiver newInsideReceiver() throws IllegalActionException { 1516 if (_director == null) { 1517 throw new IllegalActionException(this, 1518 "Cannot create a receiver without a director."); 1519 } 1520 1521 return _director.newReceiver(); 1522 } 1523 1524 /** Create a new IOPort with the specified name. 1525 * The container of the port is set to this actor. 1526 * This method is write-synchronized on the workspace. 1527 * 1528 * @param name The name for the new port. 1529 * @return The new port. 1530 * @exception NameDuplicationException If the actor already has a port 1531 * with the specified name. 1532 */ 1533 @Override 1534 public Port newPort(String name) throws NameDuplicationException { 1535 try { 1536 _workspace.getWriteAccess(); 1537 1538 IOPort port = new IOPort(this, name); 1539 return port; 1540 } catch (IllegalActionException ex) { 1541 // This exception should not occur, so we throw a runtime 1542 // exception. 1543 throw new InternalErrorException(this, ex, null); 1544 } finally { 1545 _workspace.doneWriting(); 1546 } 1547 } 1548 1549 /** Return a new receiver of a type compatible with the executive director. 1550 * Derived classes may further specialize this to return a receiver 1551 * specialized to the particular actor. This method is <i>not</i> 1552 * synchronized on the workspace, so the caller should be. 1553 * 1554 * @exception IllegalActionException If there is no executive director. 1555 * @return A new object implementing the Receiver interface. 1556 */ 1557 @Override 1558 public Receiver newReceiver() throws IllegalActionException { 1559 Director director = getExecutiveDirector(); 1560 1561 if (director == null) { 1562 throw new IllegalActionException(this, 1563 "Cannot create a receiver without an executive director."); 1564 } 1565 1566 return director.newReceiver(); 1567 } 1568 1569 /** Create a new IORelation with the specified name, add it to the 1570 * relation list, and return it. Derived classes can override 1571 * this to create domain-specific subclasses of IORelation. 1572 * This method is write-synchronized on the workspace. 1573 * 1574 * @exception IllegalActionException If name argument is null. 1575 * @exception NameDuplicationException If name collides with a name 1576 * already on the container's contents list. 1577 */ 1578 @Override 1579 public ComponentRelation newRelation(String name) 1580 throws IllegalActionException, NameDuplicationException { 1581 try { 1582 _workspace.getWriteAccess(); 1583 1584 IORelation relation = new IORelation(this, name); 1585 return relation; 1586 } finally { 1587 _workspace.doneWriting(); 1588 } 1589 } 1590 1591 /** Return an enumeration of the output ports. 1592 * Note that this method returns the ports directly 1593 * contained by this actor, whether they are transparent or not. 1594 * This method is read-synchronized on the workspace. 1595 * @return An enumeration of IOPort objects. 1596 */ 1597 @Override 1598 public List outputPortList() { 1599 try { 1600 _workspace.getReadAccess(); 1601 1602 if (_outputPortsVersion != _workspace.getVersion()) { 1603 _cachedOutputPorts = new LinkedList<IOPort>(); 1604 1605 Iterator<?> ports = portList().iterator(); 1606 1607 while (ports.hasNext()) { 1608 IOPort p = (IOPort) ports.next(); 1609 1610 if (p.isOutput()) { 1611 _cachedOutputPorts.add(p); 1612 } 1613 } 1614 1615 _outputPortsVersion = _workspace.getVersion(); 1616 } 1617 1618 return _cachedOutputPorts; 1619 } finally { 1620 _workspace.doneReading(); 1621 } 1622 } 1623 1624 /** If this actor is opaque, invoke the postfire() method of its 1625 * local director and transfer output data. 1626 * Specifically, transfer any data from the output ports of this composite 1627 * to the ports connected on the outside. The transfer is accomplished 1628 * by calling the transferOutputs() method of the executive director. 1629 * If there is no executive director, then no transfer occurs. 1630 * This method is read-synchronized on the workspace. 1631 * 1632 * @return True if the execution can continue into the next iteration. 1633 * @exception IllegalActionException If there is no director, 1634 * or if the director's postfire() method throws it, or if this 1635 * actor is not opaque. 1636 */ 1637 @Override 1638 public boolean postfire() throws IllegalActionException { 1639 if (_debugging) { 1640 _debug("Calling postfire()"); 1641 } 1642 1643 try { 1644 _workspace.getReadAccess(); 1645 1646 if (!isOpaque()) { 1647 throw new IllegalActionException(this, 1648 "Cannot postfire a non-opaque actor."); 1649 } 1650 1651 // First invoke piggybacked methods. 1652 boolean result = true; 1653 if (_piggybacks != null) { 1654 // Invoke the postfire() method of each piggyback. 1655 for (Executable piggyback : _piggybacks) { 1656 result = result && piggyback.postfire(); 1657 } 1658 } 1659 if (_derivedPiggybacks != null) { 1660 // Invoke the postfire() method of each piggyback. 1661 for (Executable piggyback : _derivedPiggybacks) { 1662 result = result && piggyback.postfire(); 1663 } 1664 } 1665 1666 // Note that this is assured of firing the local director, 1667 // not the executive director, because this is opaque. 1668 result = result && getDirector().postfire(); 1669 1670 if (_debugging) { 1671 _debug("Postfire returns " + result); 1672 } 1673 1674 return result; 1675 } finally { 1676 _workspace.doneReading(); 1677 } 1678 } 1679 1680 /** If this actor is opaque, invoke the prefire() method of the local 1681 * director. This method returns true if the actor is ready to fire 1682 * (determined by the prefire() method of the director). 1683 * It is read-synchronized on the workspace. 1684 * 1685 * @exception IllegalActionException If there is no director, 1686 * or if the director's prefire() method throws it, or if this actor 1687 * is not opaque. 1688 */ 1689 @Override 1690 public boolean prefire() throws IllegalActionException { 1691 if (_debugging) { 1692 _debug("CompositeActor: Calling prefire()"); 1693 } 1694 1695 try { 1696 _workspace.getReadAccess(); 1697 1698 if (!isOpaque()) { 1699 throw new IllegalActionException(this, 1700 "Cannot invoke prefire on a non-opaque actor, " 1701 + " please add a director."); 1702 } 1703 1704 // First invoke piggybacked methods. 1705 // If any piggyback method returns false, then we stop 1706 // there and return false. 1707 if (_piggybacks != null) { 1708 // Invoke the prefire method of each piggyback. 1709 for (Executable piggyback : _piggybacks) { 1710 if (!piggyback.prefire()) { 1711 if (_debugging) { 1712 _debug("CompositeActor: prefire returns false due to piggybacked object."); 1713 } 1714 return false; 1715 } 1716 } 1717 } 1718 if (_derivedPiggybacks != null) { 1719 // Invoke the prefire method of each piggyback. 1720 for (Executable piggyback : _derivedPiggybacks) { 1721 if (!piggyback.prefire()) { 1722 if (_debugging) { 1723 _debug("CompositeActor: prefire returns false due to piggybacked object."); 1724 } 1725 return false; 1726 } 1727 } 1728 } 1729 1730 boolean result = getDirector().prefire(); 1731 1732 if (_debugging) { 1733 _debug("CompositeActor: prefire returns: " + result); 1734 } 1735 return result; 1736 } finally { 1737 _workspace.doneReading(); 1738 } 1739 } 1740 1741 /** Create receivers and invoke the 1742 * preinitialize() method of the local director. If this actor is 1743 * not opaque, throw an exception. This method also resets 1744 * the protected variable _stopRequested 1745 * to false, so if a derived class overrides this method, then it 1746 * should also do that. This method is 1747 * read-synchronized on the workspace, so the preinitialize() 1748 * method of the director need not be, assuming it is only called 1749 * from here. 1750 * 1751 * @exception IllegalActionException If there is no director, or if 1752 * the director's preinitialize() method throws it, or if this actor 1753 * is not opaque. 1754 */ 1755 @Override 1756 public void preinitialize() throws IllegalActionException { 1757 _stopRequested = false; 1758 1759 if (_debugging) { 1760 _debug("Called preinitialize()"); 1761 } 1762 1763 try { 1764 _workspace.getReadAccess(); 1765 1766 // First invoke initializable methods. 1767 if (_initializables != null) { 1768 for (Initializable initializable : _initializables) { 1769 initializable.preinitialize(); 1770 } 1771 } 1772 1773 // Next invoke piggybacked methods. 1774 if (_piggybacks != null) { 1775 // Invoke the preinitialize() method of each piggyback. 1776 for (Executable piggyback : _piggybacks) { 1777 piggyback.preinitialize(); 1778 } 1779 } 1780 1781 // Fill in derived piggy backs 1782 if (_derivedPiggybacks == null) { 1783 _derivedPiggybacks = new HashSet<Executable>(); 1784 } else { 1785 _derivedPiggybacks.clear(); 1786 } 1787 _getTransparentActorPiggybacks(_derivedPiggybacks, false); 1788 if (_derivedPiggybacks.isEmpty()) { 1789 _derivedPiggybacks = null; 1790 } 1791 1792 if (_derivedPiggybacks != null) { 1793 // Invoke the preinitialize() method of each piggyback. 1794 for (Executable piggyback : _derivedPiggybacks) { 1795 piggyback.preinitialize(); 1796 } 1797 } 1798 1799 if (!isOpaque()) { 1800 if (getContainer() == null && deepEntityList().size() == 0) { 1801 // If the user runs an empty model, they get 1802 // this error message. 1803 throw new IllegalActionException(this, 1804 "Cannot preinitialize an empty model, " 1805 + "please add actors and a director."); 1806 } 1807 throw new IllegalActionException(this, 1808 "Cannot preinitialize a non-opaque actor, " 1809 + "please add a director."); 1810 } 1811 1812 if (_director == null) { 1813 throw new InternalErrorException( 1814 "Actor says it is opaque, but it has no director: " 1815 + getFullName()); 1816 } 1817 1818 // The director creates receivers in its preinitialize(), 1819 // so it should not be needed to do it here. There was a comment here: 1820 // "Undid this change temporarily since the move of createReceivers breaks HDF" 1821 // However, this change does not seem to break HDF actually. 1822 // However, commenting out this line causes some tests to fail the first 1823 // time they are run. I'm mystified. EAL 11/16/12 1824 createReceivers(); 1825 1826 // Note that this is assured of firing the local director, 1827 // not the executive director, because this is opaque. 1828 getDirector().preinitialize(); 1829 1830 } finally { 1831 _workspace.doneReading(); 1832 } 1833 } 1834 1835 /** Record a firing event. 1836 * @param type The firing event to be recorded. 1837 */ 1838 @Override 1839 public void recordFiring(FiringEvent.FiringEventType type) { 1840 _actorFiring(new FiringEvent(null, this, type)); 1841 } 1842 1843 /** Register a "published port" coming from a publisher. The name 1844 * is the name being used in the 1845 * matching process to match publisher and subscriber. A 1846 * subscriber interested in the output of this publisher uses 1847 * the same name. This registration process of publisher 1848 * typically happens before the model is preinitialized, 1849 * for example when opening the model. The subscribers 1850 * will look for publishers during the preinitialization phase. 1851 * @param name The name is being used in the matching process 1852 * to match publisher and subscriber. 1853 * @param port The published port. 1854 * @exception NameDuplicationException If the published port 1855 * is already registered. 1856 * @exception IllegalActionException If the published port can't 1857 * be added. 1858 */ 1859 public void registerPublisherPort(String name, IOPort port) 1860 throws NameDuplicationException, IllegalActionException { 1861 registerPublisherPort(name, port, false); 1862 } 1863 1864 /** Register a "published port" coming from a publisher. The name 1865 * is the name being used in the 1866 * matching process to match publisher and subscriber. A 1867 * subscriber interested in the output of this publisher uses 1868 * the same name. This registration process of publisher 1869 * typically happens before the model is preinitialized, 1870 * for example when opening the model. The subscribers 1871 * will look for publishers during the preinitialization phase. 1872 * This call is ignored if this composite is a class definition 1873 * or is within a class definition. 1874 * 1875 * @param name The name is being used in the matching process 1876 * to match publisher and subscriber. 1877 * @param port The published port. 1878 * @param global If true, publish globally. If false, publish 1879 * only to subscribers that are fired by the same director. 1880 * @exception NameDuplicationException If the published port 1881 * is already registered. 1882 * @exception IllegalActionException If the published port can't 1883 * be added. 1884 */ 1885 public void registerPublisherPort(String name, IOPort port, boolean global) 1886 throws NameDuplicationException, IllegalActionException { 1887 NamedObj container = getContainer(); 1888 if (isWithinClassDefinition()) { 1889 return; 1890 } 1891 // NOTE: The following strategy is fragile in that if 1892 // a director is added or removed later, then things will break. 1893 // Hence, HierarchyListeners need to be notified when 1894 // directors are added or removed. 1895 if (!isOpaque() && container instanceof CompositeActor) { 1896 // Published ports are not propagated if this actor 1897 // is opaque. 1898 ((CompositeActor) container).registerPublisherPort(name, port, 1899 global); 1900 } else { 1901 if (_publishedPorts == null) { 1902 _publishedPorts = new HashMap<String, Set<IOPort>>(); 1903 } 1904 Set<IOPort> portList = _publishedPorts.get(name); 1905 if (portList == null) { 1906 portList = new LinkedHashSet<IOPort>(); 1907 _publishedPorts.put(name, portList); 1908 } 1909 1910 if (!portList.contains(port)) { 1911 portList.add(port); 1912 } 1913 1914 if (global && this != toplevel()) { 1915 1916 // In addition, if the publisher is set to perform an 1917 // "export" then we should create a new port in this 1918 // composite and register it with our container, and 1919 // also link on the inside to the publisher relation 1920 // corresponding to the port passed in. Check the 1921 // container of port argument, which is presumably a 1922 // Publisher actor, for the value of an "export" 1923 // parameter. That parameter will have an integer 1924 // value. If the value is GLOBAL_EXPORT_LEVEL (-1). If 1925 // it is 0 (the default), then don't do the following. 1926 // If it is 1, then export only one level up 1927 // (transparent level? opaque level?). If it is 2, 1928 // export two levels up, etc. FIXME: For now, assume 1929 // name collisions will not occur. 1930 String portName = "_publisher_" 1931 + StringUtilities.sanitizeName(name); 1932 IOPort publisherPort = (IOPort) getPort(portName); 1933 if (publisherPort == null) { 1934 publisherPort = (IOPort) newPort(portName); 1935 new Parameter(publisherPort, "_hide", BooleanToken.TRUE); 1936 // Also make sure the port does not show up on the inside. 1937 new Parameter(publisherPort, "_hideInside", 1938 BooleanToken.TRUE); 1939 publisherPort.setPersistent(false); 1940 publisherPort.setOutput(true); 1941 publisherPort.setMultiport(true); 1942 } 1943 1944 // FIXME: Hide the port. Note that we need to fix vergil 1945 // so that when it lays out port, hidden ports do not take up 1946 // space on the icon. 1947 1948 // NOTE: The following will result in an _inside_ link to the port. 1949 linkToPublishedPort(name, publisherPort); 1950 1951 if (container instanceof CompositeActor) { 1952 ((CompositeActor) container).registerPublisherPort(name, 1953 publisherPort, global); 1954 } 1955 } 1956 } 1957 } 1958 1959 /** Unregister an actor firing listener. If the specified listener has not 1960 * been previously registered, then do nothing. Note that this method 1961 * is basically the same as removeDebugListener in the class NamedObj. 1962 * @param listener The listener to remove from the list of listeners 1963 * to which actor firing messages are sent. 1964 * @see #addActorFiringListener(ActorFiringListener) 1965 */ 1966 @Override 1967 public void removeActorFiringListener(ActorFiringListener listener) { 1968 if (_actorFiringListeners == null) { 1969 return; 1970 } 1971 1972 // NOTE: This has to be synchronized to prevent 1973 // concurrent modification exceptions. 1974 synchronized (_actorFiringListeners) { 1975 _actorFiringListeners.remove(listener); 1976 1977 if (_actorFiringListeners.isEmpty()) { 1978 _notifyingActorFiring = false; 1979 } 1980 1981 return; 1982 } 1983 } 1984 1985 /** Remove the specified object from the list of objects whose 1986 * preinitialize(), initialize(), and wrapup() 1987 * methods should be invoked upon invocation of the corresponding 1988 * methods of this object. If the specified object is not 1989 * on the list, do nothing. 1990 * @param initializable The object whose methods should no longer be invoked. 1991 * @see #addInitializable(Initializable) 1992 * @see #removePiggyback(Executable) 1993 */ 1994 @Override 1995 public void removeInitializable(Initializable initializable) { 1996 if (_initializables != null) { 1997 _initializables.remove(initializable); 1998 if (_initializables.size() == 0) { 1999 _initializables = null; 2000 } 2001 } 2002 } 2003 2004 /** Remove the specified object from the list of objects whose action 2005 * methods should be invoked upon invocation of the corresponding 2006 * actions methods of this object. If the specified object is not 2007 * on the list, do nothing. 2008 * @param piggyback The piggyback object. 2009 * @see #removeInitializable(Initializable) 2010 * @see #addPiggyback(Executable) 2011 */ 2012 public void removePiggyback(Executable piggyback) { 2013 if (_piggybacks != null) { 2014 _piggybacks.remove(piggyback); 2015 if (_piggybacks.size() == 0) { 2016 _piggybacks = null; 2017 } 2018 } 2019 } 2020 2021 /** Queue a change request. If there is a manager, then first call 2022 * stopFire() before deferring to the base class. 2023 * Also, if there is a waiting thread registered with the manager, 2024 * then wake it up to let it handle change requests. 2025 * @param change The requested change. 2026 */ 2027 @Override 2028 public void requestChange(ChangeRequest change) { 2029 super.requestChange(change); 2030 // stopFire() should be called after the change has been requested 2031 // to ensure that if it is being requested in a separate thread 2032 // from the director thread that it will be present in the change 2033 // queue when the director gets around to handling it. The call 2034 // to stopFire() below may wake up the director to handle it. 2035 // The call of stopFire() only needs to happen in case the change 2036 // represents a structural change. Not if we request a change to 2037 // refresh the GUI. 2038 if (getManager() != null && change.isStructuralChange()) { 2039 stopFire(); 2040 } 2041 2042 // If there is a waiting thread (e.g. synchronizeToRealTime), 2043 // then interrupt it so it can handle change requests. 2044 Manager manager = getManager(); 2045 if (manager != null) { 2046 Thread waitingThread = manager.getWaitingThread(); 2047 if (waitingThread != null) { 2048 // Instead of executing the change requests here, 2049 // just interrupt the waiting thread and expect it will 2050 // handle change requests. 2051 waitingThread.interrupt(); 2052 return; 2053 } 2054 } 2055 } 2056 2057 /** Specify whether this object is a class definition. 2058 * If the argument is true and this entity is not a class 2059 * definition, then the cache of published and subscribed ports 2060 * is cleared and the superclass called. 2061 * @param isClass True to make this object a class definition. 2062 * @exception IllegalActionException If the argument is true and 2063 * this entity contains ports with links. 2064 */ 2065 // public void setClassDefinition(boolean isClass) 2066 // throws IllegalActionException { 2067 // if (isClass && !isClassDefinition()) { 2068 // _publishedPorts = null; 2069 // _subscribedPorts = null; 2070 // _publisherRelations = null; 2071 // NamedObj immediateContainer = getContainer(); 2072 // if (immediateContainer != null 2073 // && immediateContainer instanceof CompositeActor) { 2074 // CompositeActor container = (CompositeActor)immediateContainer; 2075 // List<Port> portList = portList(); 2076 // for (Port port: portList) { 2077 // if (port instanceof PublisherPort) { 2078 // PublisherPort publisherPort = (PublisherPort)port; 2079 // try { 2080 // container.unregisterPublisherPort(publisherPort.channel.stringValue(), publisherPort, ((BooleanToken) publisherPort.global.getToken()) 2081 // .booleanValue()); 2082 // } catch (NameDuplicationException ex) { 2083 // throw new IllegalActionException(this, ex, "Could not unregister " + publisherPort); 2084 // } 2085 // } 2086 // } 2087 // } 2088 // } else if (!isClass && isClassDefinition()) { 2089 // if (_publishedPorts != null 2090 // || _subscribedPorts != null 2091 // || _publisherRelations != null) { 2092 // System.out.println("FIXME: conversion from a class definition to an instance causes problems with Publishers and Subscribers."); 2093 // } 2094 // } 2095 // super.setClassDefinition(isClass); 2096 // } 2097 2098 /** Override the base class to invalidate the schedule and 2099 * resolved types of the director. 2100 * @param container The proposed container. 2101 * @exception IllegalActionException If the action would result in a 2102 * recursive containment structure, or if 2103 * this entity and container are not in the same workspace. 2104 * @exception NameDuplicationException If the container already has 2105 * an entity with the name of this entity. 2106 */ 2107 @Override 2108 public void setContainer(CompositeEntity container) 2109 throws IllegalActionException, NameDuplicationException { 2110 // Invalidate the schedule and type resolution of the old director. 2111 Director oldDirector = getDirector(); 2112 2113 if (oldDirector != null) { 2114 oldDirector.invalidateSchedule(); 2115 oldDirector.invalidateResolvedTypes(); 2116 } 2117 2118 if (!(container instanceof CompositeActor)) { 2119 _relationWidthInference = new RelationWidthInference(this); 2120 } else { 2121 _relationWidthInference = null; 2122 } 2123 2124 // FIXME: Don't call setManager(null) here or else 2125 // java -classpath $PTII ptolemy.moml.MoMLSimpleApplication ptolemy/domains/wireless/test/auto/Zigbee.xml 2126 // will throw a NPE because MoMLParser calls 2127 // setContainer(null) if there is a problem with the 2128 // LinkVisualizer change request. 2129 2130 // However, if we don't set the manager to null, we will leak 2131 // memory here. So, our solution is to modify Manager so that 2132 // _container is a WeakReference. 2133 2134 // See https://wiki.eecs.berkeley.edu/ptexternal/Main/Main/MemoryLeaks#containerInCompositeActor 2135 super.setContainer(container); 2136 2137 Director director = getDirector(); 2138 2139 // Invalidate the schedule and type resolution of the new director. 2140 if (director != null) { 2141 director.invalidateSchedule(); 2142 director.invalidateResolvedTypes(); 2143 } 2144 } 2145 2146 /** Set the local director for execution of this CompositeActor. 2147 * Calling this method with a non-null argument makes this entity opaque. 2148 * Calling it with a null argument makes it transparent. 2149 * The container of the specified director is set to this composite 2150 * actor, and if there was previously a local director, its container 2151 * is set to null. This method is write-synchronized on the workspace. 2152 * NOTE: Calling this method is almost equivalent to calling setContainer() 2153 * on the director with this composite as an argument. The difference 2154 * is that if you call this method with a null argument, it effectively 2155 * removes the director from its role as director, but without 2156 * removing it from its container. 2157 * 2158 * @param director The Director responsible for execution. 2159 * @exception IllegalActionException If the director is not in 2160 * the same workspace as this actor. It may also be thrown in derived 2161 * classes if the director is not compatible. 2162 * @exception NameDuplicationException If an attribute already exists 2163 * in this container with the same name as the given director. 2164 * @see #getDirector() 2165 */ 2166 public void setDirector(Director director) 2167 throws IllegalActionException, NameDuplicationException { 2168 if (director != null) { 2169 director.setContainer(this); 2170 // No need to call _setDirector in here since the 2171 // director will do this directly. 2172 } else { 2173 _setDirector(null); 2174 } 2175 } 2176 2177 /** Set the Manager for execution of this CompositeActor. 2178 * This can only be done for a composite actor that has no container. 2179 * For others, the Manager is inherited from the container. 2180 * This method is write-synchronized on the workspace. 2181 * 2182 * @param manager The Manager 2183 * @exception IllegalActionException If this actor has a 2184 * container, or the manager is not in the same workspace as this 2185 * actor. 2186 * @see #getManager() 2187 */ 2188 public void setManager(Manager manager) throws IllegalActionException { 2189 if (manager != null && _workspace != manager.workspace()) { 2190 throw new IllegalActionException(this, manager, 2191 "Cannot set manager because workspaces are different." 2192 + "manager: " + manager.workspace() + ", " 2193 + _workspace); 2194 } 2195 2196 try { 2197 _workspace.getWriteAccess(); 2198 2199 if (getContainer() != null && manager != null) { 2200 throw new IllegalActionException(this, manager, 2201 "Cannot set the Manager of an actor " 2202 + "with a container."); 2203 } 2204 2205 // If there was a previous manager, we need to reset it. 2206 if (_manager != null) { 2207 // Remove this from the list of debug listeners of the old 2208 // manager. 2209 _manager.removeDebugListener(this); 2210 2211 // Notify the old manager that it is no longer the manager 2212 // of anything. 2213 _manager._makeManagerOf(null); 2214 } 2215 2216 if (manager != null) { 2217 // Add this to the list of debug listeners of the new manager. 2218 // This composite actor will relay debug messages from 2219 // the manager. 2220 manager.addDebugListener(this); 2221 manager._makeManagerOf(this); 2222 } 2223 2224 _manager = manager; 2225 return; 2226 } finally { 2227 _workspace.doneWriting(); 2228 } 2229 } 2230 2231 /** Request that execution stop as soon as possible. 2232 * This sets a flag indicating that this request has been made 2233 * (the protected variable _stopRequested). 2234 * If this actor is opaque, then invoke the 2235 * stop() method of the local director. 2236 * This method is read-synchronized on the workspace. 2237 */ 2238 @Override 2239 public void stop() { 2240 if (_debugging) { 2241 _debug("Called stop()"); 2242 } 2243 2244 try { 2245 _workspace.getReadAccess(); 2246 2247 // First invoke piggybacked methods. 2248 if (_piggybacks != null) { 2249 // Invoke the stop method of each piggyback. 2250 for (Executable piggyback : _piggybacks) { 2251 piggyback.stop(); 2252 } 2253 } 2254 if (_derivedPiggybacks != null) { 2255 // Invoke the stop method of each piggyback. 2256 for (Executable piggyback : _derivedPiggybacks) { 2257 piggyback.stop(); 2258 } 2259 } 2260 2261 _stopRequested = true; 2262 2263 if (!isOpaque()) { 2264 return; 2265 } 2266 2267 Director director = getDirector(); 2268 Director executiveDirector = getExecutiveDirector(); 2269 2270 // Call stop() on the director. Be sure the 2271 // director is an internal director, or else an infinite 2272 // loop will result! 2273 if (director != null && director != executiveDirector) { 2274 director.stop(); 2275 } 2276 } finally { 2277 _workspace.doneReading(); 2278 } 2279 } 2280 2281 /** Request that execution of the current iteration complete. 2282 * If this actor is opaque, then invoke the stopFire() 2283 * method of the local director, if there is one. 2284 * Otherwise, do nothing. 2285 * This method is read-synchronized on the workspace. 2286 */ 2287 @Override 2288 public void stopFire() { 2289 if (_debugging) { 2290 _debug("Called stopFire()"); 2291 } 2292 2293 try { 2294 _workspace.getReadAccess(); 2295 2296 // First invoke piggybacked methods. 2297 if (_piggybacks != null) { 2298 // Invoke the stopFire() method of each piggyback. 2299 for (Executable piggyback : _piggybacks) { 2300 piggyback.stopFire(); 2301 } 2302 } 2303 if (_derivedPiggybacks != null) { 2304 // Invoke the stopFire() method of each piggyback. 2305 for (Executable piggyback : _derivedPiggybacks) { 2306 piggyback.stopFire(); 2307 } 2308 } 2309 2310 if (!isOpaque()) { 2311 return; 2312 } 2313 2314 Director director = getDirector(); 2315 Director executiveDirector = getExecutiveDirector(); 2316 2317 // Call stopFire() on the director. Be sure the 2318 // director is an internal director, or else an infinite 2319 // loop will result! 2320 if (director != null && director != executiveDirector) { 2321 director.stopFire(); 2322 } 2323 } finally { 2324 _workspace.doneReading(); 2325 } 2326 } 2327 2328 /** If this is an opaque CompositeActor, then look to our director 2329 * for help. If we are transparent, then we really shouldn't have been 2330 * called, so just ignore. 2331 */ 2332 @Override 2333 public void terminate() { 2334 if (_debugging) { 2335 _debug("Called terminate()"); 2336 } 2337 2338 // First invoke piggybacked methods. 2339 if (_piggybacks != null) { 2340 // Invoke the terminate() method of each piggyback. 2341 for (Executable piggyback : _piggybacks) { 2342 piggyback.terminate(); 2343 } 2344 } 2345 if (_derivedPiggybacks != null) { 2346 // Invoke the terminate() method of each piggyback. 2347 for (Executable piggyback : _derivedPiggybacks) { 2348 piggyback.terminate(); 2349 } 2350 } 2351 2352 if (!isOpaque()) { 2353 return; 2354 } 2355 2356 getDirector().terminate(); 2357 } 2358 2359 /** Unlink the subscriberPort with a already registered "published port" coming 2360 * from a publisher. The name is the name being used in the 2361 * matching process to match publisher and subscriber. A 2362 * subscriber interested in the output of this publisher uses 2363 * the name. This registration process of publisher 2364 * typically happens before the model is preinitialized, 2365 * for example when opening the model. The subscribers 2366 * will look for publishers during the preinitialization phase. 2367 * @param name The name is being used in the matching process 2368 * to match publisher and subscriber. 2369 * @param subscriberPort The subscribed port. 2370 * @exception IllegalActionException If the published port cannot be found. 2371 */ 2372 public void unlinkToPublishedPort(String name, IOPort subscriberPort) 2373 throws IllegalActionException { 2374 NamedObj container = getContainer(); 2375 if (!isOpaque() && container instanceof CompositeActor 2376 && !((CompositeActor) container).isWithinClassDefinition()) { 2377 // Published ports are not propagated if this actor 2378 // is opaque. 2379 ((CompositeActor) container).unlinkToPublishedPort(name, 2380 subscriberPort); 2381 } else { 2382 // Remove the link to a previous relation, if necessary. 2383 2384 IORelation relation = _publisherRelations != null 2385 ? _publisherRelations.get(name) 2386 : null; 2387 2388 if (relation != null) { 2389 subscriberPort.unlink(relation); 2390 notifyConnectivityChange(); 2391 } 2392 2393 Director director = getDirector(); 2394 if (director != null) { 2395 director.invalidateSchedule(); 2396 director.invalidateResolvedTypes(); 2397 } 2398 } 2399 } 2400 2401 /** Unlink the subscriberPort with a already registered "published port" coming 2402 * from a publisher. The name is the name being used in the 2403 * matching process to match publisher and subscriber. A 2404 * subscriber interested in the output of this publisher uses 2405 * the name. This registration process of publisher 2406 * typically happens before the model is preinitialized, 2407 * for example when opening the model. The subscribers 2408 * will look for publishers during the preinitialization phase. 2409 * @param name The name is being used in the matching process 2410 * to match publisher and subscriber. 2411 * @param subscriberPort The subscribed port. 2412 * @param global Specification of whether the data is subscribed 2413 * globally. If set to true, then subscribers will see values 2414 * published by publishers anywhere in the model that reference 2415 * the same channel by name. If set to false, then only values 2416 * published by publishers that are fired by the same director 2417 * are seen by this subscriber. 2418 * @exception IllegalActionException If the published port cannot be found. 2419 */ 2420 public void unlinkToPublishedPort(String name, IOPort subscriberPort, 2421 boolean global) throws IllegalActionException { 2422 NamedObj container = getContainer(); 2423 if (!isOpaque() && container instanceof CompositeActor 2424 && !((CompositeActor) container).isWithinClassDefinition()) { 2425 // Published ports are not propagated if this actor 2426 // is opaque. 2427 ((CompositeActor) container).unlinkToPublishedPort(name, 2428 subscriberPort, global); 2429 } else { 2430 // Remove the link to a previous relation, if necessary. 2431 2432 IORelation relation = _publisherRelations != null 2433 ? _publisherRelations.get(name) 2434 : null; 2435 2436 if (relation != null) { 2437 subscriberPort.unlink(relation); 2438 notifyConnectivityChange(); 2439 } 2440 2441 Director director = getDirector(); 2442 if (director != null) { 2443 director.invalidateSchedule(); 2444 director.invalidateResolvedTypes(); 2445 } 2446 2447 if (global && container instanceof CompositeActor) { 2448 for (Object relationObj : subscriberPort.linkedRelationList()) { 2449 try { 2450 for (Object port : ((IORelation) relationObj) 2451 .linkedPortList(subscriberPort)) { 2452 2453 IOPort subscribedPort = (IOPort) port; 2454 if (subscribedPort.isInput()) { 2455 ((CompositeActor) container) 2456 .unlinkToPublishedPort(name, 2457 subscribedPort, global); 2458 2459 subscribedPort.setContainer(null); 2460 2461 } 2462 } 2463 ((IORelation) relationObj).setContainer(null); 2464 notifyConnectivityChange(); 2465 } catch (NameDuplicationException ex) { 2466 throw new InternalErrorException( 2467 subscriberPort.getContainer(), ex, 2468 "Failed to set the container to null?"); 2469 } 2470 } 2471 } 2472 } 2473 } 2474 2475 /** Unlink the subscriberPort with a already registered "published port" coming 2476 * from a publisher. The pattern is the pattern being used in the 2477 * matching process to match publisher and subscriber. A 2478 * subscriber interested in the output of this publisher uses 2479 * the name. This registration process of publisher 2480 * typically happens before the model is preinitialized, 2481 * for example when opening the model. The subscribers 2482 * will look for publishers during the preinitialization phase. 2483 * @param pattern The pattern is being used in the matching process 2484 * to match publisher and subscriber. 2485 * @param subscriberPort The subscribed port. 2486 * @exception IllegalActionException If the published port cannot be found. 2487 */ 2488 public void unlinkToPublishedPort(Pattern pattern, 2489 TypedIOPort subscriberPort) throws IllegalActionException { 2490 NamedObj container = getContainer(); 2491 if (!isOpaque() && container instanceof CompositeActor 2492 && !((CompositeActor) container).isWithinClassDefinition()) { 2493 // Published ports are not propagated if this actor 2494 // is opaque. 2495 ((CompositeActor) container).unlinkToPublishedPort(pattern, 2496 subscriberPort); 2497 } else { 2498 if (_publishedPorts != null) { 2499 for (String name : _publishedPorts.keySet()) { 2500 Matcher matcher = pattern.matcher(name); 2501 if (matcher.matches()) { 2502 unlinkToPublishedPort(name, subscriberPort); 2503 } 2504 } 2505 } 2506 2507 } 2508 } 2509 2510 /** Unlink the subscriberPort with a already registered "published port" coming 2511 * from a publisher. The pattern is the pattern being used in the 2512 * matching process to match publisher and subscriber. A 2513 * subscriber interested in the output of this publisher uses 2514 * the name. This registration process of publisher 2515 * typically happens before the model is preinitialized, 2516 * for example when opening the model. The subscribers 2517 * will look for publishers during the preinitialization phase. 2518 * @param pattern The pattern is being used in the matching process 2519 * to match publisher and subscriber. 2520 * @param subscriberPort The subscribed port. 2521 * @param global Specification of whether the data is subscribed 2522 * globally. If set to true, then subscribers will see values 2523 * published by publishers anywhere in the model that reference 2524 * the same channel by name. If set to false, then only values 2525 * published by publishers that are fired by the same director 2526 * are seen by this subscriber. 2527 * @exception IllegalActionException If the published port cannot be found. 2528 */ 2529 public void unlinkToPublishedPort(Pattern pattern, 2530 TypedIOPort subscriberPort, boolean global) 2531 throws IllegalActionException { 2532 NamedObj container = getContainer(); 2533 if (!isOpaque() && container instanceof CompositeActor 2534 && !((CompositeActor) container).isWithinClassDefinition()) { 2535 // Published ports are not propagated if this actor 2536 // is opaque. 2537 ((CompositeActor) container).unlinkToPublishedPort(pattern, 2538 subscriberPort, global); 2539 } else { 2540 2541 if (_publishedPorts != null) { 2542 for (String name : _publishedPorts.keySet()) { 2543 Matcher matcher = pattern.matcher(name); 2544 if (matcher.matches()) { 2545 unlinkToPublishedPort(name, subscriberPort); 2546 } 2547 } 2548 } 2549 2550 for (Object relationObj : subscriberPort.linkedRelationList()) { 2551 try { 2552 for (Object port : ((IORelation) relationObj) 2553 .linkedPortList(subscriberPort)) { 2554 2555 IOPort subscribedPort = (IOPort) port; 2556 if (subscribedPort.isInput()) { 2557 //if the subscribed port does not connect to any inside port, then unlink the port 2558 Set connectedInsidePort = new HashSet( 2559 subscribedPort.insidePortList()); 2560 connectedInsidePort.remove(subscriberPort); 2561 if (connectedInsidePort.size() == 0) { 2562 ((CompositeActor) container) 2563 .unlinkToPublishedPort(pattern, 2564 (TypedIOPort) subscribedPort, 2565 global); 2566 2567 subscribedPort.setContainer(null); 2568 2569 } 2570 2571 } 2572 } 2573 ((IORelation) relationObj).setContainer(null); 2574 } catch (NameDuplicationException ex) { 2575 throw new InternalErrorException( 2576 subscriberPort.getContainer(), ex, 2577 "Failed to set the container to null?"); 2578 } 2579 } 2580 } 2581 } 2582 2583 /** Unregister a "published port" coming 2584 * from a publisher. The name is the name being used in the 2585 * matching process to match publisher and subscriber. A 2586 * subscriber interested in the output of this publisher uses 2587 * the same name. This registration process of publisher 2588 * typically happens before the model is preinitialized, 2589 * for example when opening the model. The subscribers 2590 * will look for publishers during the preinitialization phase. 2591 * @param name The name is being used in the matching process 2592 * to match publisher and subscriber. This will be the port 2593 * that should be removed 2594 * @param publisherPort The publisher port. 2595 * @exception IllegalActionException If the container of the port cannot 2596 * be set. 2597 * @exception NameDuplicationException If the container of the port cannot 2598 * be set 2599 */ 2600 public void unregisterPublisherPort(String name, IOPort publisherPort) 2601 throws IllegalActionException, NameDuplicationException { 2602 unregisterPublisherPort(name, publisherPort, false); 2603 } 2604 2605 /** Unregister a "published port" coming 2606 * from a publisher. The name is the name being used in the 2607 * matching process to match publisher and subscriber. A 2608 * subscriber interested in the output of this publisher uses 2609 * the same name. This registration process of publisher 2610 * typically happens before the model is preinitialized, 2611 * for example when opening the model. The subscribers 2612 * will look for publishers during the preinitialization phase. 2613 * @param name The name is being used in the matching process 2614 * to match publisher and subscriber. This will be the port 2615 * that should be removed 2616 * @param publisherPort The publisher port. 2617 * @param global If true, unregister the port all the way up the hierarchy. 2618 * @exception IllegalActionException If the container of the port cannot 2619 * be set. 2620 * @exception NameDuplicationException If the container of the port cannot 2621 * be set 2622 */ 2623 public void unregisterPublisherPort(String name, IOPort publisherPort, 2624 boolean global) 2625 throws IllegalActionException, NameDuplicationException { 2626 NamedObj container = getContainer(); 2627 if (!isOpaque() && container instanceof CompositeActor 2628 && !((CompositeActor) container).isWithinClassDefinition()) { 2629 // Published ports are not propagated if this actor 2630 // is opaque. 2631 ((CompositeActor) container).unregisterPublisherPort(name, 2632 publisherPort); 2633 } else { 2634 if (_publishedPorts != null) { 2635 Set<IOPort> ports = _publishedPorts.get(name); 2636 // if (ports == null) { 2637 // // If we are changing the name of a Publisher channel in an 2638 // // opaque, then ports might be null. 2639 // throw new InternalErrorException("While trying to unregister " 2640 // + "port \"" + name + "\" from port \"" 2641 // + publisherPort.getFullName() 2642 // + "\", the port was not found in the map of published " 2643 // + "ports accessible in the container of the port."); 2644 // } 2645 if (ports != null) { 2646 // If we are changing the name of a Publisher channel in an 2647 // opaque, then ports might be null. 2648 ports.remove(publisherPort); 2649 if (ports.isEmpty()) { 2650 _publishedPorts.remove(name); 2651 } 2652 } 2653 } 2654 2655 if (_publisherRelations != null) { 2656 IORelation relation = _publisherRelations.get(name); 2657 if (relation != null) { 2658 if (global && container instanceof CompositeActor) { 2659 for (Object port : relation 2660 .linkedPortList(publisherPort)) { 2661 IOPort publishedPort = (IOPort) port; 2662 if (publishedPort.isOutput()) { 2663 ((CompositeActor) container) 2664 .unregisterPublisherPort(name, 2665 publishedPort, global); 2666 publishedPort.setContainer(null); 2667 } 2668 } 2669 } 2670 2671 relation.setContainer(null); 2672 2673 _publisherRelations.remove(name); 2674 } 2675 } 2676 2677 } 2678 } 2679 2680 /** If this actor is opaque, then invoke the wrapup() method of the local 2681 * director. This method is read-synchronized on the workspace. 2682 * 2683 * @exception IllegalActionException If there is no director, 2684 * or if the director's wrapup() method throws it, or if this 2685 * actor is not opaque. 2686 */ 2687 @Override 2688 public void wrapup() throws IllegalActionException { 2689 if (_debugging) { 2690 _debug("Called wrapup()"); 2691 } 2692 2693 try { 2694 _workspace.getReadAccess(); 2695 2696 // Collect exceptions during wrapup. 2697 LinkedList<Throwable> throwables = new LinkedList<Throwable>(); 2698 2699 // First invoke initializable methods. 2700 if (_initializables != null) { 2701 for (Initializable initializable : _initializables) { 2702 // Catch any exceptions so that additional wrapup methods are invoked. 2703 try { 2704 initializable.wrapup(); 2705 } catch (Throwable throwable) { 2706 throwables.add(throwable); 2707 } 2708 } 2709 } 2710 2711 // Next invoke piggybacked methods. 2712 if (_piggybacks != null) { 2713 // Invoke the wrapup() method of each piggyback. 2714 for (Executable piggyback : _piggybacks) { 2715 // Catch any exceptions so that additional wrapup methods are invoked. 2716 try { 2717 piggyback.wrapup(); 2718 } catch (Throwable throwable) { 2719 throwables.add(throwable); 2720 } 2721 } 2722 } 2723 if (_derivedPiggybacks != null) { 2724 // Invoke the wrapup() method of each piggyback. 2725 for (Executable piggyback : _derivedPiggybacks) { 2726 // Catch any exceptions so that additional wrapup methods are invoked. 2727 try { 2728 piggyback.wrapup(); 2729 } catch (Throwable throwable) { 2730 throwables.add(throwable); 2731 } 2732 } 2733 } 2734 2735 if (!isOpaque()) { 2736 // Don't throw an exception here, calling wrapup() on 2737 // a composite that is not opaque is not always an error. 2738 // Generating WebStart for ptolemy/demo/ElectricPowerSystem/ElectricPowerSystem.xml 2739 // One possibility is to add the DoNothingDirector. 2740 System.out.println( 2741 "Warning: CompositeActor.wrapup() was called on " 2742 + getFullName() 2743 + ", which is not opaque (it does not have a director?)."); 2744 } 2745 2746 // Note that this is assured of firing the local director, 2747 // not the executive director, because this is opaque. 2748 // However, there may not be a director (e.g. DifferentialSystem 2749 // actor in CT). 2750 Director director = getDirector(); 2751 2752 if (director != null) { 2753 // Catch any exceptions so that additional wrapup methods are invoked. 2754 try { 2755 director.wrapup(); 2756 } catch (Throwable throwable) { 2757 throwables.add(throwable); 2758 } 2759 } 2760 if (throwables.size() == 1) { 2761 Throwable exception = throwables.get(0); 2762 if (exception instanceof IllegalActionException) { 2763 throw (IllegalActionException)exception; 2764 } else { 2765 throw new IllegalActionException(this, exception, 2766 "Exception thrown during wrapup."); 2767 } 2768 } else if (throwables.size() > 1) { 2769 StringBuffer message = new StringBuffer(); 2770 for (Throwable throwable : throwables) { 2771 message.append(throwable.getMessage()); 2772 message.append("\n======\n"); 2773 } 2774 throw new IllegalActionException(this, throwables.get(0), 2775 "Multiple exceptions thrown during wrapup:\n" 2776 + message.toString()); 2777 } 2778 } finally { 2779 _workspace.doneReading(); 2780 } 2781 } 2782 2783 /////////////////////////////////////////////////////////////////// 2784 //// protected methods //// 2785 2786 /** Send an actor firing event to all actor firing listeners that 2787 * have registered with this actor. 2788 * @param event The event. 2789 */ 2790 protected final void _actorFiring(FiringEvent event) { 2791 if (_notifyingActorFiring) { 2792 for (ActorFiringListener listener : _actorFiringListeners) { 2793 listener.firingEvent(event); 2794 } 2795 } 2796 } 2797 2798 /** Send an actor firing event type to all actor firing listeners that 2799 * have registered with this actor. 2800 * @param type The type. 2801 * @param multiplicity The multiplicity of the firing, that is, 2802 * the number of times the firing will occur or has occurred. 2803 */ 2804 protected final void _actorFiring(FiringEvent.FiringEventType type, 2805 int multiplicity) { 2806 _actorFiring(new FiringEvent(null, this, type, multiplicity)); 2807 } 2808 2809 /** Add an actor to this container with minimal error checking. 2810 * This overrides the base-class method to make sure the argument 2811 * implements the Actor interface. 2812 * It is <i>not</i> synchronized on the workspace, so the 2813 * caller should be. 2814 * 2815 * @param entity Actor to contain. 2816 * @exception IllegalActionException If the actor has no name, or the 2817 * action would result in a recursive containment structure, or the 2818 * argument does not implement the Actor interface. 2819 * @exception NameDuplicationException If the name collides with a name 2820 * already on the actor contents list. 2821 */ 2822 @Override 2823 protected void _addEntity(ComponentEntity entity) 2824 throws IllegalActionException, NameDuplicationException { 2825 if (!(entity instanceof Actor)) { 2826 throw new IllegalActionException(this, entity, 2827 "CompositeActor can only contain entities that " 2828 + " implement the Actor interface."); 2829 } 2830 2831 super._addEntity(entity); 2832 } 2833 2834 /** Add a port to this actor. This overrides the base class to 2835 * throw an exception if the added port is not an instance of 2836 * IOPort. This method should not be used directly. Call the 2837 * setContainer() method of the port instead. This method does not set 2838 * the container of the port to point to this actor. 2839 * It assumes that the port is in the same workspace as this 2840 * actor, but does not check. The caller should check. 2841 * This method is <i>not</i> synchronized on the workspace, so the 2842 * caller should be. 2843 * 2844 * @param port The port to add to this actor. 2845 * @exception IllegalActionException If the port class is not 2846 * acceptable to this actor, or the port has no name. 2847 * @exception NameDuplicationException If the port name collides with a 2848 * name already in the actor. 2849 */ 2850 @Override 2851 protected void _addPort(Port port) 2852 throws IllegalActionException, NameDuplicationException { 2853 if (!(port instanceof IOPort)) { 2854 throw new IllegalActionException(this, port, 2855 "CompositeActor can only contain instances of IOPort."); 2856 } 2857 2858 super._addPort(port); 2859 } 2860 2861 /** Add a relation to this container. This method should not be used 2862 * directly. Call the setContainer() method of the relation instead. 2863 * This method does not set the container of the relation to refer 2864 * to this container. This method is <i>not</i> synchronized on the 2865 * workspace, so the caller should be. 2866 * 2867 * @param relation Relation to contain. 2868 * @exception IllegalActionException If the relation has no name, or is 2869 * not an instance of IORelation. 2870 * @exception NameDuplicationException If the name collides with a name 2871 * already on the contained relations list. 2872 */ 2873 @Override 2874 protected void _addRelation(ComponentRelation relation) 2875 throws IllegalActionException, NameDuplicationException { 2876 if (!(relation instanceof IORelation)) { 2877 throw new IllegalActionException(this, relation, 2878 "CompositeActor can only contain instances of IORelation."); 2879 } 2880 2881 super._addRelation(relation); 2882 } 2883 2884 /** Notify this actor that the given entity has been added inside it. 2885 * This overrides the base-class method to invalidate the schedule 2886 * and type resolution, and to request initialization with the director. 2887 * This method does not alter the actor in any way. 2888 * It is <i>not</i> synchronized on the workspace, so the 2889 * caller should be. 2890 * 2891 * @param entity Actor to contain. 2892 */ 2893 @Override 2894 protected void _finishedAddEntity(ComponentEntity entity) { 2895 Director director = getDirector(); 2896 2897 if (director != null) { 2898 director.invalidateSchedule(); 2899 director.invalidateResolvedTypes(); 2900 director.requestInitialization((Actor) entity); 2901 } 2902 } 2903 2904 /** Set the local director for execution of this CompositeActor. 2905 * This should not be called be directly. Instead, call setContainer() 2906 * on the director. This method removes any previous director 2907 * from this container, and caches a local reference to the director 2908 * so that this composite does not need to search its attributes each 2909 * time the director is accessed. 2910 * @param director The Director responsible for execution. 2911 * @exception IllegalActionException If removing the old director 2912 * causes this to be thrown. Should not be thrown. 2913 * @exception NameDuplicationException If removing the old director 2914 * causes this to be thrown. Should not be thrown. 2915 */ 2916 protected void _setDirector(Director director) 2917 throws IllegalActionException, NameDuplicationException { 2918 Director oldDirector = getDirector(); 2919 2920 if (director != oldDirector) { 2921 if (oldDirector != null) { 2922 oldDirector.invalidateSchedule(); 2923 oldDirector.invalidateResolvedTypes(); 2924 } 2925 } 2926 // Do not use getDirector() to get the old director because 2927 // that will look up the hierarchy if there is no director. 2928 if (director != _director) { 2929 // If we are changing from opaque to transparent or 2930 // vice versa, then we need to notify of a hierarchy change. 2931 if (director == null || oldDirector == null) { 2932 _notifyHierarchyListenersBeforeChange(); 2933 } 2934 } 2935 Director previousLocalDirector = _director; 2936 try { 2937 if (director != oldDirector) { 2938 _director = director; 2939 2940 if (director != null) { 2941 director.invalidateSchedule(); 2942 director.invalidateResolvedTypes(); 2943 } else { 2944 // When deleting, the executive director also needs to be 2945 // notified that its schedule must be recomputed. 2946 Director executiveDirector = getExecutiveDirector(); 2947 2948 if (executiveDirector != null) { 2949 executiveDirector.invalidateSchedule(); 2950 } 2951 } 2952 } 2953 } finally { 2954 // If we are changing from opaque to transparent or 2955 // vice versa, then we need to notify of a hierarchy change. 2956 if (director == null || previousLocalDirector == null) { 2957 _notifyHierarchyListenersAfterChange(); 2958 } 2959 } 2960 } 2961 2962 /** Read inputs from ParameterPorts and update. 2963 * @exception IllegalActionException If reading from parameter associated 2964 * with port fails. 2965 */ 2966 protected void _transferPortParameterInputs() 2967 throws IllegalActionException { 2968 // Need to read from port parameters 2969 // first because in some domains (e.g. SDF) 2970 // the behavior of the schedule might depend on rate variables 2971 // set from ParameterPorts. 2972 for (Iterator<?> inputPorts = inputPortList().iterator(); inputPorts 2973 .hasNext() && !_stopRequested;) { 2974 IOPort p = (IOPort) inputPorts.next(); 2975 2976 if (p instanceof ParameterPort) { 2977 ((ParameterPort) p).getParameter().update(); 2978 } 2979 } 2980 } 2981 2982 /////////////////////////////////////////////////////////////////// 2983 //// private methods //// 2984 2985 /** Fill in the piggybacks in the contained transparent CompositeActors. 2986 * If addPiggyBackAtThisLevel equals to True, the piggybacks directly in 2987 * this composite actor will also be included. 2988 * @param piggybacks The piggybacks that will be filled it. 2989 * @param addPiggyBackAtThisLevel True when the piggybacks directly in this composite 2990 * actor should also be included. 2991 */ 2992 private void _getTransparentActorPiggybacks(Set<Executable> piggybacks, 2993 boolean addPiggyBackAtThisLevel) { 2994 assert piggybacks != null; 2995 if (addPiggyBackAtThisLevel && _piggybacks != null) { 2996 piggybacks.addAll(_piggybacks); 2997 } 2998 for (CompositeActor actor : entityList(CompositeActor.class)) { 2999 if (!actor.isOpaque()) { 3000 actor._getTransparentActorPiggybacks(piggybacks, true); 3001 } 3002 } 3003 } 3004 3005 /** Return the RelationWidthInference algorithm. 3006 * _relationWidthInference is only stored at the top CompositeActor 3007 * for the complete model. 3008 * @return The RelationWidthInference algorithm. 3009 * @exception KernelRuntimeException If toplevel not a CompositeActor. 3010 */ 3011 private RelationWidthInference _getWidthInferenceAlgorithm() { 3012 NamedObj container = getContainer(); 3013 if (container instanceof CompositeActor) { 3014 return ((CompositeActor) container)._getWidthInferenceAlgorithm(); 3015 } else { 3016 // assert _relationWidthInference != null; 3017 // Removed the assert. When your cloning this object it is possible 3018 // that _relationWidthInference hasn't been filled in yet. 3019 // If _relationWidthInference is null, then running newly created models 3020 // will fail. See 7.1.5 in CompositeActor.tcl 3021 return _relationWidthInference; 3022 } 3023 } 3024 3025 /////////////////////////////////////////////////////////////////// 3026 //// public variables //// 3027 3028 /////////////////////////////////////////////////////////////////// 3029 //// protected variables //// 3030 3031 /** The list of ActorFiringListeners registered with this object. 3032 * NOTE: Because of the way we synchronize on this object, it should 3033 * never be reset to null after the first list is created. 3034 */ 3035 protected LinkedList<ActorFiringListener> _actorFiringListeners = null; 3036 3037 /** The causality interface, if it has been created. */ 3038 protected CausalityInterface _causalityInterface; 3039 3040 /** The derived piggybacked executables. Derived piggybacked executables 3041 * are executables that are added to transparent composite actors that are 3042 * contained by this composite actor. These should also piggy back on this actor. 3043 * These are only filled in if this actor is a opaque composite actor.*/ 3044 protected transient Set<Executable> _derivedPiggybacks; 3045 3046 /** List of objects whose (pre)initialize() and wrapup() methods 3047 * should be slaved to these. 3048 */ 3049 protected transient Set<Initializable> _initializables; 3050 3051 /** Flag that is true if there are actor firing listeners. */ 3052 protected boolean _notifyingActorFiring = false; 3053 3054 /** List piggybacked objects. */ 3055 protected transient Set<Executable> _piggybacks; 3056 3057 /** Keep track of all published ports accessible in this container.*/ 3058 protected Map<String, Set<IOPort>> _publishedPorts; 3059 3060 /** Keep track of all published ports accessible in this container.*/ 3061 protected Map<String, List<IOPort>> _subscribedPorts; 3062 3063 /** Keep track of all relations with published ports accessible in this container.*/ 3064 protected Map<String, IORelation> _publisherRelations; 3065 3066 /** Indicator that a stop has been requested by a call to stop(). */ 3067 protected boolean _stopRequested = false; 3068 3069 /////////////////////////////////////////////////////////////////// 3070 //// private variables //// 3071 3072 // The director for this composite actor. 3073 private Director _director; 3074 3075 // Indicator that we are in the connectionsChanged method. 3076 private boolean _inConnectionsChanged = false; 3077 3078 // The manager for this composite actor. 3079 private Manager _manager; 3080 3081 // Cached lists of input and output ports. 3082 private transient long _inputPortsVersion = -1; 3083 3084 private transient List<IOPort> _cachedInputPorts; 3085 3086 private transient long _outputPortsVersion = -1; 3087 3088 private transient List<IOPort> _cachedOutputPorts; 3089 3090 /** The director for which the causality interface was created. */ 3091 private Director _causalityInterfaceDirector; 3092 3093 /** Record of the workspace version the last time receivers were created. */ 3094 private long _receiversVersion = -1; 3095 3096 /* A helper class that does the width inference. 3097 * _relationWidthInference is only stored at the top CompositeActor 3098 * for the complete model. 3099 */ 3100 private RelationWidthInference _relationWidthInference; 3101 3102}