001/* Add "this." to certain places in the script parameter of a JavaScript actor. 002 003 Copyright (c) 2016-2018 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 */ 028package ptolemy.moml.filter; 029 030import java.lang.reflect.Method; 031 032import ptolemy.kernel.util.NamedObj; 033import ptolemy.kernel.util.Settable; 034import ptolemy.moml.MoMLParser; 035 036/////////////////////////////////////////////////////////////////// 037//// JavaScriptThisUpdate 038 039/** 040 * Add "this." to certain places in the script parameter of a JavaScript actor. 041 * 042 * <p>This class will eventually be removed after we have updated the files.</p> 043 * 044 * <p>To update a model, try:</p> 045 * <pre> 046 * $PTII/bin/ptinvoke ptolemy.vergil.basic.imprt.accessor.ReloadAccessors model.xml 047 * </pre> 048 * 049 * To update all the models that contain JavaScript actors: 050 * <pre> 051 * # Generate a list of all the text files in the ptII tree, excluding certain directories like vendors. 052 * $PTII/adm/bin/ptIItxtfiles <& /tmp/f 053 * 054 * # Generate a list of all of the .xml files. 055 * cat /tmp/f | egrep '.xml$' < /tmp/x 056 * 057 * # Generate a list of all the .xml files that contain the JavaScript actor. 058 * cat /tmp/x | xargs egrep 'ptolemy.actor.lib.jjs.JavaScript' | awk -F ':' '{print $1}' | sort | uniq < /tmp/javascriptx 059 * 060 * # Reload the accessors on all the .xml files that contain the JavaScript actor, 061 * # which as a side effect runs the Backward Compatibility script 062 * cat /tmp/jsaccessorx | xargs $PTII/bin/ptinvoke ptolemy.vergil.basic.imprt.accessor.ReloadAccessors 063 * </pre> 064 * 065 * <p>We use <code>ptinvoke</code> to set the classpath.</p> 066 * 067 * <p>ReloadAccessors, opens a model, reloads all the accessors (if any) and 068 * saves the model. While opening the model, the BackwardCompatibility MoML 069 * filters are run. This class can be one of those filters.</p> 070 * 071 * @author Christopher Brooks 072 * @version $Id$ 073 * @since Ptolemy II 11.0 074 * @Pt.ProposedRating Yellow (eal) 075 * @Pt.AcceptedRating Red (cxh) 076 */ 077public class JavaScriptThisUpdate extends MoMLFilterSimple { 078 079 /////////////////////////////////////////////////////////////////// 080 //// public methods //// 081 082 /** Handle parameter name changes. 083 * @param container The container for XML element. 084 * @param element The XML element name. 085 * @param attributeName The name of the attribute. 086 * @param attributeValue The value of the attribute. 087 * @param xmlFile The file currently being parsed. 088 * @return A new value for the attribute, or the same value 089 * to leave it unchanged, or null to cause the current element 090 * to be ignored (unless the attributeValue argument is null). 091 */ 092 @Override 093 public String filterAttributeValue(NamedObj container, String element, 094 String attributeName, String attributeValue, String xmlFile) { 095 return attributeValue; 096 } 097 098 /** If the container is a property named "script" contained 099 * by the JavaScript actor, then add "this." to certain 100 * function calls. 101 * @param container The object defined by the element that this 102 * is the end of. 103 * @param elementName The element name. 104 * @param currentCharData The character data, which appears 105 * only in the doc and configure elements 106 * @param xmlFile The file currently being parsed. 107 * @exception Exception if there is a problem substituting 108 * in the new value. 109 */ 110 @Override 111 public void filterEndElement(NamedObj container, String elementName, 112 StringBuffer currentCharData, String xmlFile) throws Exception { 113 114 // Fix the background color of the ViewScreen actor. 115 // Note that the ViewScreen actor also has a name change. 116 if (container != null && container.getName().equals("script")) { 117 NamedObj actor = container.getContainer(); 118 119 if (actor != null && actor.getClass().getName() 120 .startsWith("ptolemy.actor.lib.jjs.JavaScript")) { 121 String value = ((Settable) container).getExpression().trim(); 122 123 // Prepend "this." to keywords that have leading whitespace. 124 for (int i = 0; i < _keywords.length; i++) { 125 value = value.replaceAll(" " + _keywords[i] + "\\(", 126 " this." + _keywords[i] + "("); 127 value = value.replaceAll("\t" + _keywords[i] + "\\(", 128 "\tthis." + _keywords[i] + "("); 129 } 130 131 // If the old and new values are different, then print them out 132 // and mark the container as modified. 133 String previousValue = ((Settable) container).getExpression() 134 .trim(); 135 if (!value.equals(previousValue)) { 136 System.out.println( 137 "JavaScriptThisUpdate: " + actor.getFullName() 138 + " has a script:\n" + previousValue); 139 System.out.println("That has been updated to:\n" + value); 140 // $PTII/ptolemy/util/test/Diff.java is not necessarily present. 141 if (_diff != null) { 142 System.out.println("The diff is:\n"); 143 System.out.println(_diff.invoke(null, 144 ((Settable) container).getExpression().trim(), 145 value)); 146 } 147 ((Settable) container).setExpression(value); 148 MoMLParser.setModified(true); 149 } 150 } 151 } 152 } 153 154 /** Return a string that describes what the filter does. 155 * @return A description of the filter (ending with a newline). 156 */ 157 @Override 158 public String toString() { 159 return getClass().getName() 160 + ": Update script parameter of the JavaScript actor " 161 + "by adding \"this.\" to certain locations"; 162 } 163 164 // Keywords that get "this." prepended if the have leading 165 // whitespace. 166 private static String[] _keywords = { "addInputHandler", "connect", 167 "extend", "get", "getParameter", "getResource", "implement", 168 "input", "instantiate", "output", "parameter", "removeInputHandler", 169 "send", "setDefault", "setParameter" }; 170 171 static { 172 try { 173 Class diffClass = Class.forName("ptolemy.util.test.Diff"); 174 _diff = diffClass.getDeclaredMethod("diff", 175 new Class[] { String.class, String.class }); 176 } catch (ClassNotFoundException ex) { 177 System.err.println( 178 "JavaScriptThisUpdated could not find ptolemy.util.test.Diff, so diffs will not be printed."); 179 } catch (NoSuchMethodException ex2) { 180 System.err.println( 181 "JavaScriptThisUpdated could not find ptolemy.util.test.Diff.diff(String, String), so diffs will not be printed."); 182 } 183 184 } 185 186 /////////////////////////////////////////////////////////////////// 187 //// protected variables //// 188 189 /** The ptolemy.util.test.Diff.diff(String, String) method. */ 190 protected static Method _diff = null; 191}