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