001/* A Ptolemy application that instantiates class names given on the command
002 line.
003
004 Copyright (c) 1999-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.actor.gui;
030
031import java.awt.Color;
032import java.awt.event.WindowAdapter;
033import java.awt.event.WindowEvent;
034import java.util.Iterator;
035import java.util.LinkedList;
036import java.util.List;
037
038import ptolemy.actor.CompositeActor;
039import ptolemy.actor.Manager;
040import ptolemy.actor.injection.PortablePlaceable;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.util.StringUtilities;
043
044///////////////////////////////////////////////////////////////////
045//// CompositeActorApplication
046
047/**
048 This application creates one or more Ptolemy II models given a
049 classname on the command line, and then executes those models, each in
050 its own thread.  Each specified class should be derived from
051 CompositeActor, and should have a constructor that takes a single
052 argument, an instance of Workspace.  If the model does not contain
053 a manager, then one will be created for it. The model is displayed using
054 an instance of ModelFrame, which provides controls for executing
055 the model and setting its top-level and director parameters.
056 <p>
057 The command-line arguments can also set parameter values for any
058 parameter in the models, with the name given relative to the top-level
059 entity.  For example, to specify the iteration count in an SDF model,
060 you can invoke this on the command line as follows:
061 <pre>
062 java -classpath $PTII ptolemy.actor.gui.CompositeActorApplication \
063 -director.iterations 1000 \
064 -class ptolemy.domains.sdf.demo.Butterfly.Butterfly
065 </pre>
066 This assumes that the model given by the specified class name has a director
067 named "director" with a parameter named "iterations".  If more than
068 one model is given on the command line, then the parameter values will
069 be set for all models that have such a parameter.
070 <p>
071 This class keeps count the number of open windows.  The waitForFinish
072 method can then be used to determine when all of the windows opened by
073 this class have been closed.  The main() method exits the application
074 when all windows have been closed.
075
076 @see ModelFrame
077 @author Edward A. Lee, Brian K. Vogel, and Steve Neuendorffer
078 @version $Id$
079 @since Ptolemy II 0.4
080 @Pt.ProposedRating Yellow (cxh)
081 @Pt.AcceptedRating Red (vogel)
082 */
083public class CompositeActorApplication extends CompositeActorSimpleApplication {
084    ///////////////////////////////////////////////////////////////////
085    ////                         public methods                    ////
086
087    /** Close any ModeFrames opened in processArgs().
088     */
089    public void close() {
090        // Mainly used for testing.
091        for (ModelFrame frame : _frames) {
092            if (frame != null) {
093                frame.close();
094            }
095        }
096    }
097
098    /** Create a new application with the specified command-line arguments.
099     *  @param args The command-line arguments.
100     */
101    public static void main(String[] args) {
102        CompositeActorApplication application = new CompositeActorApplication();
103        _run(application, args);
104    }
105
106    /** Parse the command-line arguments, creating models as specified.
107     *  @param args The command-line arguments.
108     *  @exception Exception If something goes wrong.
109     */
110    @Override
111    public void processArgs(String[] args) throws Exception {
112        if (args != null) {
113            _parseArgs(args);
114
115            // start the models.
116            Iterator models = _models.iterator();
117
118            while (models.hasNext()) {
119                _frames.add(
120                        (ModelFrame) startRun((CompositeActor) models.next()));
121            }
122        }
123    }
124
125    /** If the specified model has a manager and is not already running,
126     *  then execute the model in a new thread.  Otherwise, do nothing.
127     *  If the model contains an atomic entity that implements Placeable,
128     *  we create create an instance of ModelFrame, if nothing implements
129     *  Placeable, then we do not create an instance of ModelFrame.  This
130     *  allows us to run non-graphical models on systems that do not have
131     *  a display.
132     *  <p>
133     *  We then start the model running.
134     *
135     *  @param model The model to execute.
136     *  @return The ModelFrame that for the model.
137     *  @see ptolemy.actor.Manager#startRun()
138     */
139    @Override
140    public synchronized Object startRun(CompositeActor model) {
141        // This method is synchronized so that it can atomically modify
142        // the count of executing processes.
143        // NOTE: If you modify this method, please be sure that it
144        // will work for non-graphical models in the nightly test suite.
145        // Iterate through the model, looking for something that is Placeable.
146        boolean hasPlaceable = false;
147        Iterator atomicEntities = model.allAtomicEntityList().iterator();
148
149        while (atomicEntities.hasNext()) {
150            Object object = atomicEntities.next();
151
152            if (object instanceof Placeable
153                    || object instanceof PortablePlaceable) {
154                hasPlaceable = true;
155                break;
156            }
157        }
158
159        ModelFrame frame = null;
160        if (hasPlaceable) {
161            // The model has an entity that is Placeable, so create a frame.
162            try {
163                frame = new ModelFrame(model);
164                _openCount++;
165                frame.addWindowListener(new WindowAdapter() {
166                    @Override
167                    public void windowClosed(WindowEvent event) {
168                        synchronized (CompositeActorApplication.this) {
169                            _openCount--;
170                            CompositeActorApplication.this.notifyAll();
171
172                            // FIXME: is this right?  We need
173                            // to exit if all the windows are closed?
174                            if (_openCount == 0) {
175                                StringUtilities.exit(0);
176                            }
177                        }
178                    }
179                });
180                frame.setBackground(new Color(0xe5e5e5));
181                frame.pack();
182                frame.centerOnScreen();
183                frame.setVisible(true);
184
185                // FIXME: Use a JFrame listener to determine when all windows
186                // are closed.
187            } catch (Exception ex) {
188                System.out.println("startRun: " + ex);
189            }
190        }
191
192        Manager manager = model.getManager();
193
194        if (manager != null) {
195            try {
196                manager.startRun();
197            } catch (IllegalActionException ex) {
198                // Model is already running.  Ignore.
199            }
200        } else {
201            report("Model " + model.getFullName() + " cannot be executed "
202                    + "because it does not have a manager.");
203        }
204        return frame;
205    }
206
207    ///////////////////////////////////////////////////////////////////
208    ////                         private variables                 ////
209
210    // List of ModelFrames created processArgs();
211    private List<ModelFrame> _frames = new LinkedList<ModelFrame>();
212}