001/* An application that executes non-graphical 002 models specified on the command line. 003 004 Copyright (c) 2009-2013 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.moml; 030 031import java.io.File; 032 033import ptolemy.actor.CompositeActor; 034import ptolemy.actor.Director; 035import ptolemy.actor.Manager; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.Settable; 039import ptolemy.moml.filter.BackwardCompatibility; 040import ptolemy.moml.filter.RemoveGraphicalClasses; 041 042////////////////////////////////////////////////////////////////////////// 043//// MoMLCommandLineApplication 044 045/** A application that reads command line arguments that set parameters 046 and a .xml file naming a model, sets the parameters and runs the model. 047 048 <p>MoMLApplication sets the look and feel, which starts up Swing, 049 so we can't use MoMLApplication for non-graphical simulations. 050 051 <p>The parent class, @{link ptolemy.moml.MoMLSimpleApplication} does 052 not handle command line parameters that set parameters 053 054 For example to use this class, try: 055 <pre> 056 java -classpath $PTII ptolemy.moml.MoMLCommandLineApplication -myParameter '&quot;Hello, World.&quot;' test/MoMLCommandLineApplicationTest.xml 057 </pre> 058or 059 <pre> 060 $PTII/bin/ptinvoke ptolemy.moml.MoMLCommandLineApplication -myParameter '"&quot;Hellow, World.&quot;"' test/MoMLCommandLineApplicationTest.xml 061 </pre> 062 <p> 063 If a Ptolemy model is instantiated on the command line, either 064 by giving a MoML file or a -class argument, then parameters of that 065 model can be set on the command line. The syntax is: 066 <pre> 067 $PTII/bin/ptinvoke ptolemy.moml.MoMLCommandLineApplication -<i>parameterName</i> <i>value</i> <i>modelFile.xml</i> 068 </pre> 069 where <i>parameterName</i> is the name of a parameter relative to 070 the top level of a model or the director of a model. For instance, 071 if foo.xml defines a toplevel entity named <code>x</code> and 072 <code>x</code> contains an entity named <code>y</code> and a 073 parameter named <code>a</code>, and <code>y</code> contains a 074 parameter named <code>b</code>, then: 075 <pre> 076 $PTII/bin/ptinvoke ptolemy.moml.MoMLCommandLineApplication -a 5 -y.b 10 foo.xml 077 </pre> 078 would set the values of the two parameters. 079 080 <p>Note that strings need to be carefully backslashed, so to set a 081 parameter named <code>c</code> to the string <code>"bar"</code> it 082 might be necessary to do something like: 083 <pre> 084 $PTII/bin/ptinvoke ptolemy.moml.MoMLCommandLineApplication -a 5 -y.b 10 -c '"&quot;bar&quot;" foo.xml 085 </pre> 086 The reason the single quotes and double quotes are necessary is because <code>ptinvoke</code> 087 is a shell script which tends to strip off the double quotes. 088 089 @author Christopher Brooks 090 @version $Id$ 091 @since Ptolemy II 8.0 092 @Pt.ProposedRating Red (cxh) 093 @Pt.AcceptedRating Red (eal) 094 */ 095public class MoMLCommandLineApplication extends MoMLSimpleApplication { 096 097 /** Parse a MoML file that contains a model, update the parameters 098 * and run the model. 099 * @param args An array of strings, where the last element names 100 * a MoML file that contains a Ptolemy II model. The string should be 101 * a relative pathname. Other elements may name model parameters 102 * and values for the parameters. Parameter names should begin 103 * with a "-" and be followed by the value for the parameter. 104 * @exception Throwable If there was a problem parsing 105 * or running the model. 106 */ 107 public MoMLCommandLineApplication(String[] args) throws Throwable { 108 MoMLParser parser = new MoMLParser(); 109 110 // The test suite calls MoMLSimpleApplication multiple times, 111 // and the list of filters is static, so we reset it each time 112 // so as to avoid adding filters every time we run an auto test. 113 // We set the list of MoMLFilters to handle Backward Compatibility. 114 MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters()); 115 116 // Filter out any graphical classes. 117 MoMLParser.addMoMLFilter(new RemoveGraphicalClasses()); 118 119 // If there is a MoML error, then throw the exception as opposed 120 // to skipping the error. If we call StreamErrorHandler instead, 121 // then the nightly build may fail to report MoML parse errors 122 // as failed tests 123 //parser.setErrorHandler(new StreamErrorHandler()); 124 // We use parse(URL, URL) here instead of parseFile(String) 125 // because parseFile() works best on relative pathnames and 126 // has problems finding resources like files specified in 127 // parameters if the xml file was specified as an absolute path. 128 CompositeActor toplevel = (CompositeActor) parser.parse(null, 129 new File(args[args.length - 1]).toURI().toURL()); 130 131 _manager = new Manager(toplevel.workspace(), "MoMLSimpleApplication"); 132 toplevel.setManager(_manager); 133 toplevel.addChangeListener(this); 134 _manager.addExecutionListener(this); 135 136 // This code is very similar to code in 137 // ptolemy.actor.gui.MoMLApplication 138 String parameterName = null; 139 String parameterValue = null; 140 for (int i = 0; i < args.length - 1; i++) { 141 String arg = args[i]; 142 if (arg.trim().startsWith("-")) { 143 if (i >= args.length - 1) { 144 throw new IllegalActionException( 145 "Cannot set " + "parameter " + arg 146 + " when no value is " + "given."); 147 } 148 149 // Save in case this is a parameter name and value. 150 parameterName = arg.substring(1); 151 parameterValue = args[i + 1]; 152 153 // First, see if there are any attributes in the top level 154 Attribute attribute = toplevel.getAttribute(parameterName); 155 if (attribute instanceof Settable) { 156 // Use a MoMLChangeRequest so that visual rendition (if 157 // any) is updated and listeners are notified. 158 String moml = "<property name=\"" + parameterName 159 + "\" value=\"" + parameterValue + "\"/>"; 160 MoMLChangeRequest request = new MoMLChangeRequest(this, 161 toplevel, moml); 162 toplevel.requestChange(request); 163 } 164 165 // Now try for parameters in the director 166 Director director = toplevel.getDirector(); 167 168 if (director != null) { 169 attribute = director.getAttribute(parameterName); 170 171 if (attribute instanceof Settable) { 172 // Use a MoMLChangeRequest so that visual rendition (if 173 // any) is updated and listeners are notified. 174 String moml = "<property name=\"" + parameterName 175 + "\" value=\"" + parameterValue + "\"/>"; 176 MoMLChangeRequest request = new MoMLChangeRequest(this, 177 director, moml); 178 director.requestChange(request); 179 } 180 } 181 i++; 182 } else { 183 // Unrecognized option. 184 throw new IllegalActionException("Unrecognized option: " + arg); 185 } 186 } 187 188 // See http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4178 189 // "error handling with MoMLCommandLineApplication" 190 _manager.run(); 191 192 // PtExecuteApplication uses _activeCount to determine when 193 // the models are done. We can't do that here because 194 // executeError() might be called from a different thread. 195 // PtExecuteApplication handles this by deferring the change 196 // to the Swing event thread. We don't have a Swing event thread, 197 // so we are stuck with a busy loop. 198 while (!_executionFinishedOrError) { 199 Thread.yield(); 200 } 201 202 if (_sawThrowable != null) { 203 throw _sawThrowable; 204 } 205 } 206 207 /** Create an instance of a single model and run it. 208 * @param args The command-line arguments naming the .xml file to run 209 */ 210 public static void main(String[] args) { 211 try { 212 new MoMLCommandLineApplication(args); 213 } catch (Throwable ex) { 214 System.err.println("Command failed: " + ex); 215 ex.printStackTrace(); 216 } 217 } 218}