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}