001/* An application that executes non-graphical 002 models specified on the command line. 003 004 Copyright (c) 2008-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.moml; 030 031import java.io.File; 032import java.util.List; 033 034import ptolemy.actor.TypedCompositeActor; 035import ptolemy.kernel.ComponentEntity; 036import ptolemy.kernel.util.ChangeListener; 037import ptolemy.kernel.util.ChangeRequest; 038import ptolemy.moml.filter.BackwardCompatibility; 039 040/////////////////////////////////////////////////////////////////// 041//// ConvertToLazy 042 043/** Read a specified MoML file and convert all instances of 044 * TypedCompositeActor that contain more than a specified 045 * number of entities to LazyTypedCompositeActor. The 046 * converted model's MoML is produced on standard out. 047 * To use this on the command line, invoke as follows: 048 * <pre> 049 * $PTII/bin/convertToLazy inputMoML.xml <i>numberOfEntities</i> > outputMoML.xml 050 * </pre> 051 * or 052 * <pre> 053 * java -classpath $PTII ptolemy.moml.ConvertToLazy inputMoML.xml <i>numberOfEntities</i> > outputMoML.xml 054 * </pre> 055 * If the <i>numberOfEntities</i> argument is not supplied, then it 056 * defaults to 100. 057 058 @author Edward A. Lee 059 @version $Id$ 060 @since Ptolemy II 8.0 061 @Pt.ProposedRating Red (cxh) 062 @Pt.AcceptedRating Red (eal) 063 */ 064public class ConvertToLazy implements ChangeListener { 065 066 /** Parse the xml file and convert it. 067 * @param xmlFileName A string that refers to an MoML file that 068 * contains a Ptolemy II model. The string should be 069 * a relative pathname. 070 * @param threshold The number of contained entities that a composite 071 * should have to be converted to a lazy composite. 072 * @exception Throwable If there was a problem parsing 073 * or running the model. 074 */ 075 public ConvertToLazy(String xmlFileName, int threshold) throws Throwable { 076 MoMLParser parser = new MoMLParser(); 077 078 // Save the current MoMLFilters before conversion so that if 079 // we call this class from within a larger application, we don't 080 // change the filters. 081 List oldFilters = MoMLParser.getMoMLFilters(); 082 try { 083 // The test suite calls UseLazyCompositeApplication multiple times, 084 // and the list of filters is static, so we reset it each time 085 // so as to avoid adding filters every time we run an auto test. 086 // We set the list of MoMLFilters to handle Backward Compatibility. 087 MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters()); 088 089 // If there is a MoML error, then throw the exception as opposed 090 // to skipping the error. If we call StreamErrorHandler instead, 091 // then the nightly build may fail to report MoML parse errors 092 // as failed tests 093 //parser.setErrorHandler(new StreamErrorHandler()); 094 // We use parse(URL, URL) here instead of parseFile(String) 095 // because parseFile() works best on relative pathnames and 096 // has problems finding resources like files specified in 097 // parameters if the xml file was specified as an absolute path. 098 TypedCompositeActor toplevel = (TypedCompositeActor) parser 099 .parse(null, new File(xmlFileName).toURI().toURL()); 100 convert(toplevel, threshold); 101 102 // We export and then reparse and then export again so 103 // that the resulting MoML has the <configure> 104 // ...</configure> blocks. If just exportMoML, then the moml will 105 // not have the <configure> ...</configure> blocks because the 106 // LazyTypedCompositeActor._exportMoMLContents() method is not 107 // called. See ConvertToLazy-1.1 in test/ConvertToLazy.tcl 108 // where we check that the moml has "configure" in it. 109 String moml = toplevel.exportMoML(); 110 parser.resetAll(); 111 toplevel = (TypedCompositeActor) parser.parse(moml); 112 System.out.println(toplevel.exportMoML()); 113 114 } finally { 115 MoMLParser.setMoMLFilters(oldFilters); 116 } 117 } 118 119 /////////////////////////////////////////////////////////////////// 120 //// Public methods //// 121 122 /** React to a change request has been successfully executed by 123 * doing nothing. This method is called after a change request 124 * has been executed successfully. In this class, we 125 * do nothing. 126 * @param change The change that has been executed, or null if 127 * the change was not done via a ChangeRequest. 128 */ 129 @Override 130 public void changeExecuted(ChangeRequest change) { 131 } 132 133 /** React to a change request that has resulted in an exception. 134 * This method is called after a change request was executed, 135 * but during the execution in an exception was thrown. 136 * This method throws a runtime exception with a description 137 * of the original exception. 138 * @param change The change that was attempted or null if 139 * the change was not done via a ChangeRequest. 140 * @param exception The exception that resulted. 141 */ 142 @Override 143 public void changeFailed(ChangeRequest change, Exception exception) { 144 // If we do not implement ChangeListener, then ChangeRequest 145 // will print any errors to stdout and continue. 146 // This causes no end of trouble with the test suite 147 // We can't throw an Exception here because this method in 148 // the base class does not throw Exception. 149 String description = ""; 150 151 if (change != null) { 152 description = change.getDescription(); 153 } 154 155 System.err.println("UseLazyCompositeApplication.changeFailed(): " 156 + description + " failed:\n" + exception); 157 } 158 159 /** Convert the model. 160 * @param actor The model to convert. 161 * @param threshold The threshold to use. 162 */ 163 public void convert(TypedCompositeActor actor, int threshold) { 164 List<ComponentEntity> entities = actor.entityList(); 165 for (ComponentEntity entity : entities) { 166 if (entity instanceof TypedCompositeActor) { 167 // Do the conversion depth-first. 168 convert((TypedCompositeActor) entity, threshold); 169 if (entity.getClassName() 170 .equals("ptolemy.actor.TypedCompositeActor") 171 && count((TypedCompositeActor) entity) >= threshold) { 172 entity.setClassName( 173 "ptolemy.actor.LazyTypedCompositeActor"); 174 } 175 } 176 } 177 // List<ComponentEntity> classDefinitions = actor.classDefinitionList(); 178 // for (ComponentEntity classDefinition : classDefinitions) { 179 // if (classDefinition instanceof TypedCompositeActor) { 180 // // Do the conversion depth-first. 181 // convert((TypedCompositeActor) classDefinition, threshold); 182 // if (classDefinition.getClassName().equals( 183 // "ptolemy.actor.TypedCompositeActor") 184 // && count((TypedCompositeActor) classDefinition) >= threshold) { 185 // classDefinition 186 // .setClassName("ptolemy.actor.LazyTypedCompositeActor"); 187 // } 188 // } 189 // } 190 191 } 192 193 /** Count the number of contained entities that have not already been made 194 * lazy. 195 * @param actor The actor to count. 196 * @return The number of contained entities (deeply) that are not already 197 * lazy. 198 */ 199 public int count(TypedCompositeActor actor) { 200 int result = 0; 201 List<ComponentEntity> entities = actor.entityList(); 202 for (ComponentEntity entity : entities) { 203 result++; 204 if (entity instanceof TypedCompositeActor && !entity.getClassName() 205 .equals("ptolemy.actor.lib.LazyTypedCompositeActor")) { 206 result += count((TypedCompositeActor) entity); 207 } 208 } 209 return result; 210 } 211 212 /** Create an instance of a model and convert it. 213 * @param args The command-line arguments providing the number 214 * of entities threshold and naming the .xml file to convert. 215 */ 216 public static void main(String[] args) { 217 try { 218 if (args.length == 0) { 219 System.err.println("Usage: FIXME MoMLFile <numberOfEnties>\n"); 220 return; 221 } 222 if (args.length == 1) { 223 new ConvertToLazy(args[0], 10); 224 return; 225 } 226 int threshold = Integer.parseInt(args[1]); 227 new ConvertToLazy(args[0], threshold); 228 } catch (Throwable ex) { 229 System.err.println("Command failed: " + ex); 230 ex.printStackTrace(); 231 } 232 } 233}