001/* A composite actor that executes a submodel in fire().
002
003 Copyright (c) 2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027
028 */
029package ptolemy.actor.lib.hoc;
030
031import ptolemy.actor.Manager;
032import ptolemy.actor.TypedCompositeActor;
033import ptolemy.actor.TypedIOPort;
034import ptolemy.actor.gui.Effigy;
035import ptolemy.actor.gui.PtolemyEffigy;
036import ptolemy.data.ActorToken;
037import ptolemy.data.type.BaseType;
038import ptolemy.kernel.CompositeEntity;
039import ptolemy.kernel.Entity;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.KernelException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.kernel.util.StringAttribute;
044
045///////////////////////////////////////////////////////////////////
046//// ExecuteActor
047
048/**
049 This is a composite actor that can execute the contained model
050 completely, as if it were a top-level model, on each firing.
051 This can be used to define an actor whose firing behavior
052 is given by a complete execution of a submodel.
053 <p>
054 An instance of this actor can have ports added to it.  If it has
055 input ports, then on each firing, before executing the referenced
056 model, this actor will read an input token from the input port, if
057 there is one, and use it to set the value of a top-level parameter
058 in the contained model that has the same name as the port, if there
059 is one.  The simplest way to ensure that there is a matching parameter
060 is to use a PortParameter for inputs.  However, this actor will work
061 also for ordinary ports. In this case, if this actor has a
062 parameter with the same name as the port, and it is an instance
063 of Variable (or its derived class Parameter), then the token
064 read at the input is moved into it using its setToken() method.
065 Otherwise, if it is an instance of Settable, then a string representation
066 of the token is copied using the setExpression() method.
067 Input ports should not be multiports, and if they are, then
068 all but the first channel will be ignored.
069 <p>
070 If this actor has output ports and the contained model is executed,
071 then upon completion of that execution, if this actor has parameters
072 whose names match those of the output ports, then the final value of
073 those parameters is sent to the output ports. If such a parameter is an
074 instance of Variable (or its derived class Parameter), then its
075 contained token is sent to the output token. Otherwise, if it is an
076 instance of Settable, then a string token is produced on the output
077 with its value equal to that returned by getExpression() of the
078 Settable. Output ports should not be multiports. If they are,
079 then all but the first channel will be ignored.
080 A typical use of this actor will use the SetVariable actor
081 inside to define the value of the output port.
082 <p>
083 In preinitialize(), type constraints are set up so that input
084 and output ports with (name) matching parameters are constrained
085 to have compatible types. Note that if the ports or parameters
086 are changed during execution, then it will be necessary to set
087 up matching type constraints by hand.  Since this isn't possible
088 to do from Vergil, the ports and parameters of this actor
089 should not be changed using Vergil during execution.
090 <p>
091 This actor also overrides the requestChange() method and the
092 executeChangeRequests() method to execute the given change. It does not
093 delegate the change request to the container, but executes the request
094 immediately or records it, depending on whether setDeferringChangeRequests()
095 has been called with a true argument.
096
097 @author Edward A. Lee
098 @version $Id$
099 @since Ptolemy II 10.0
100 @see ModelReference
101 @see ptolemy.actor.lib.SetVariable
102 @Pt.ProposedRating Yellow (eal)
103 @Pt.AcceptedRating Red (eal)
104 */
105public class ExecuteActor extends RunCompositeActor {
106
107    /** Construct a RunCompositeActor with a name and a container.
108     *  The container argument must not be null, or a
109     *  NullPointerException will be thrown.  This actor will use the
110     *  workspace of the container for synchronization and version counts.
111     *  If the name argument is null, then the name is set to the empty string.
112     *  Increment the version of the workspace.  This actor will have no
113     *  local director initially, and its executive director will be simply
114     *  the director of the container.
115     *
116     *  @param container The container.
117     *  @param name The name of this actor.
118     *  @exception IllegalActionException If the container is incompatible
119     *   with this actor.
120     *  @exception NameDuplicationException If the name coincides with
121     *   an actor already in the container.
122     */
123    public ExecuteActor(CompositeEntity container, String name)
124            throws IllegalActionException, NameDuplicationException {
125        super(container, name);
126
127        actor = new TypedIOPort(this, "actor", true, false);
128        actor.setTypeEquals(BaseType.ACTOR);
129        StringAttribute cardinal = new StringAttribute(actor, "_cardinal");
130        cardinal.setExpression("SOUTH");
131    }
132
133    ///////////////////////////////////////////////////////////////////
134    ////                         parameters                        ////
135
136    /** Input port on which to receive an actor. This has type actor.
137     */
138    public TypedIOPort actor;
139
140    ///////////////////////////////////////////////////////////////////
141    ////                         public methods                    ////
142
143    /** Make this actor opaque. */
144    @Override
145    public boolean isOpaque() {
146        return true;
147    }
148
149    /** Override the base class to not set type constraints between the
150     *  output ports and parameters of the actor.
151     *  This actor cannot manage type inference across independent models,
152     *  so the types have to be set by hand.
153     *  @exception IllegalActionException If there is no director, or if
154     *   the director's preinitialize() method throws it, or if this actor
155     *   is not opaque.
156     */
157    @Override
158    public void preinitialize() throws IllegalActionException {
159        // Do not call super.preinitialize().
160        _stopRequested = false;
161
162        Effigy parentEffigy = Effigy.findToplevelEffigy(this);
163        if (parentEffigy != null) {
164            try {
165                parentEffigy.workspace().getWriteAccess();
166                _wrapperEffigy = new PtolemyEffigy(parentEffigy,
167                        parentEffigy.uniqueName("_wrapperEffigy"));
168            } catch (NameDuplicationException e) {
169                throw new IllegalActionException(this, e,
170                        "Unable to create an " + "effigy for the model.");
171            } finally {
172                parentEffigy.workspace().doneWriting();
173            }
174        }
175
176        if (_debugging) {
177            _debug("Called preinitialize()");
178        }
179    }
180
181    ///////////////////////////////////////////////////////////////////
182    ////                         protected methods                 ////
183
184    /** Run a complete execution of the model provided on the actor port.
185     *  @exception IllegalActionException If the execution throws it.
186     *  @return One of COMPLETED or STOP_ITERATING.
187     */
188    @Override
189    protected int _executeInsideModel() throws IllegalActionException {
190        if (actor.hasToken(0)) {
191            Entity entity = ((ActorToken) actor.get(0)).getEntity();
192            if (!(entity instanceof TypedCompositeActor)) {
193                throw new IllegalActionException(this,
194                        "actor input has to specify a TypedCompositeActor.");
195            }
196            _model = (TypedCompositeActor) entity;
197
198            // In case we are running headless.
199            if (_wrapperEffigy != null) {
200                _wrapperEffigy.setModel(_model);
201            }
202
203            Manager manager = new Manager("_manager");
204            _model.setManager(manager);
205
206            _readInputs();
207            try {
208                manager.execute();
209            } catch (KernelException e) {
210                throw new IllegalActionException(this, e, "Execution failed.");
211            }
212            _writeOutputs();
213
214            if (_debugging) {
215                _debug("---- Firing is complete.");
216            }
217        }
218        return COMPLETED;
219    }
220
221    /** Return the actor whose life cycle is being managed by this actor,
222     *  which is the most recently received actor on the actor input port.
223     *  @return This.
224     */
225    @Override
226    protected TypedCompositeActor _getManagedActor() {
227        return _model;
228    }
229
230    ///////////////////////////////////////////////////////////////////
231    ////                         private variables                 ////
232
233    /** The most recently received actor on the actor input port. */
234    private TypedCompositeActor _model;
235
236    /** The effigy to execute models at run time. */
237    private PtolemyEffigy _wrapperEffigy;
238}