001/* Filter for Parameter name changes. 002 003 Copyright (c) 2003-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 027 */ 028package ptolemy.moml.filter; 029 030import java.util.HashMap; 031import java.util.Iterator; 032import java.util.Map; 033 034import ptolemy.kernel.util.NamedObj; 035import ptolemy.moml.MoMLParser; 036 037/////////////////////////////////////////////////////////////////// 038//// ParameterNameChanges 039 040/** When this class is registered with the MoMLParser.setMoMLFilter() 041 method, it will cause MoMLParser to filter so that models from 042 earlier releases will run in the current release. 043 044 <p>This class will filter for classes with Parameters where the parameter 045 name has changed. 046 047 <p>For example, after Ptolemy II 2.2, the PNDirector 048 changed in such a way that the 'Initial_queue_capacity' parameter 049 is now 'initialQueueCapacity'. 050 051 <p>To add this 052 change to this filter, we add a code to the static section at 053 the bottom of the file. 054 <pre> 055 // PNDirectory: After 2.2, 'Initial_queue_capacity' 056 // property is now 'initialQueueCapacity' 057 058 HashMap pnDirectorChanges = new HashMap<String, String>(); 059 // Key = property name, Value = new class name 060 pnDirectorChanges.put("Initial_queue_capacity", 061 "initialQueueCapacity"); 062 </pre> 063 The pnDirectorChange HashMap maps property names to the new 064 name 065 066 <pre> 067 068 _classesWithParameterNameChanges 069 .put("ptolemy.domains.pn.PNDirectory", 070 pnDirectorChanges); 071 </pre> 072 The _classesWithParameterNameChanges HashMap contains all the classes 073 such as PNDirector that have changes and each class has a map 074 of the Parameter changes that are to be made. 075 076 <p> Conceptually, how the code works is that when we see a class while 077 parsing, we check to see if the class is in _classesWithParameterNameChanges. 078 If the class was present in the HashMap, then as we go through the 079 code, we look for property names that need to have their classes changed. 080 081 <p>NOTE: This class and PortNameChange might conflict if 082 a port and parameter have the same name. 083 084 @author Christopher Hylands 085 @version $Id$ 086 @since Ptolemy II 2.2 087 @Pt.ProposedRating Red (cxh) 088 @Pt.AcceptedRating Red (cxh) 089 */ 090public class ParameterNameChanges extends MoMLFilterSimple { 091 /** If the attributeName is "class" and attributeValue names a 092 * class that has had a Parameter names changed between releases, 093 * then substitute in the new Parameter names. 094 * 095 * @param container The container for this attribute. 096 * in this method. 097 * @param element The XML element name. 098 * @param attributeName The name of the attribute. 099 * @param attributeValue The value of the attribute. 100 * @param xmlFile The file currently being parsed. 101 * @return the value of the attributeValue argument. 102 */ 103 @Override 104 public String filterAttributeValue(NamedObj container, String element, 105 String attributeName, String attributeValue, String xmlFile) { 106 // This method gets called many times by the MoMLParser, 107 // so we try to be smart about the number of comparisons 108 // and we try to group comparisons together so that we 109 // are not making the same comparison more than once. 110 if (attributeValue == null) { 111 // attributeValue == null is fairly common, so we check for 112 // that first 113 return null; 114 } 115 116 if (attributeName.equals("name")) { 117 // Save the name for later use if we see a "class" 118 _lastNameSeen = attributeValue; 119 120 if (_currentlyProcessingActorWithParameterNameChanges) { 121 if (_propertyMap != null 122 && _propertyMap.containsKey(attributeValue)) { 123 // We will do the above checks only if we found a 124 // class that had property class changes. 125 _newName = (String) _propertyMap.get(attributeValue); 126 127 if (!attributeValue.equals(_newName)) { 128 MoMLParser.setModified(true); 129 } 130 131 return _newName; 132 } else { 133 return attributeValue; 134 } 135 } 136 } 137 138 // If you change this class, you should run before and after 139 // timing tests on large moml files, a good command to run 140 // is: 141 // $PTII/bin/ptolemy -test $PTII/ptolemy/domains/ct/demo/CarTracking/CarTracking.xml 142 // which will open up a large xml file and then close after 2 seconds. 143 if (attributeName.equals("class")) { 144 if (_classesWithParameterNameChanges.containsKey(attributeValue)) { 145 // We found a class with a parameter name change. 146 _currentlyProcessingActorWithParameterNameChanges = true; 147 148 // Coverity says that container could be null. 149 String containerName = (container == null ? "" 150 : container.getFullName()); 151 152 _currentActorFullName = containerName + "." + _lastNameSeen; 153 _propertyMap = _classesWithParameterNameChanges 154 .get(attributeValue); 155 } else if (_currentlyProcessingActorWithParameterNameChanges 156 && _newName != null) { 157 // We found a property class to change, and now we 158 // found the class itself that needs changing. 159 // Only return the new class once, but we might 160 // have other properties that need changing 161 //_currentlyProcessingActorWithParameterNameChanges = false; 162 // String temporaryNewClass = _newName; 163 // if (!attributeValue.equals(_newName)) { 164 // MoMLParser.setModified(true); 165 // } 166 _newName = null; 167 } else if (_currentlyProcessingActorWithParameterNameChanges 168 && container != null 169 && !container.getFullName().equals(_currentActorFullName) 170 && !container.getFullName() 171 .startsWith(_currentActorFullName)) { 172 // We found another class in a different container 173 // while handling a class with port name changes 174 _currentlyProcessingActorWithParameterNameChanges = false; 175 } 176 } 177 178 return attributeValue; 179 } 180 181 /** In this class, do nothing. 182 * @param container The object created by this element. 183 * @param elementName The element name. 184 * @param currentCharData The character data, which appears 185 * only in the doc and configure elements 186 * @param xmlFile The file currently being parsed. 187 * @exception Exception Not thrown in this base class. 188 */ 189 @Override 190 public void filterEndElement(NamedObj container, String elementName, 191 StringBuffer currentCharData, String xmlFile) throws Exception { 192 } 193 194 /** Return a string that describes what the filter does. 195 * @return the description of the filter that ends with a newline. 196 */ 197 @Override 198 public String toString() { 199 StringBuffer results = new StringBuffer(getClass().getName() 200 + ": Update any Parameter names\n" + "that have been renamed.\n" 201 + "Below are the actors that are affected, along " 202 + "with the Parameter name \nand the new name:\n"); 203 for (Map.Entry<String, HashMap<String, String>> classChange : _classesWithParameterNameChanges 204 .entrySet()) { 205 String actor = classChange.getKey(); 206 results.append("\t" + actor + "\n"); 207 208 HashMap<String, String> propertyMap = classChange.getValue(); 209 210 Iterator propertiesMapEntries = propertyMap.entrySet().iterator(); 211 212 while (propertiesMapEntries.hasNext()) { 213 Map.Entry properties = (Map.Entry) propertiesMapEntries.next(); 214 String oldProperty = (String) properties.getKey(); 215 String newProperty = (String) properties.getValue(); 216 results.append( 217 "\t\t" + oldProperty + "\t -> " + newProperty + "\n"); 218 } 219 } 220 221 return results.toString(); 222 } 223 224 /////////////////////////////////////////////////////////////////// 225 //// private variables //// 226 // Map of actor names a HashMap of property names to new classes. 227 private static HashMap<String, HashMap<String, String>> _classesWithParameterNameChanges; 228 229 // The the full name of the actor we are currently processing 230 private String _currentActorFullName; 231 232 // Set to true if we are currently processing an actor with parameter 233 // class changes, set to false when we are done. 234 private boolean _currentlyProcessingActorWithParameterNameChanges = false; 235 236 // Last "name" value seen, for use if we see a "class". 237 private String _lastNameSeen; 238 239 // The new name for the property we are working on. 240 private String _newName; 241 242 // Cache of map from old property names to new class names for 243 // the actor we are working on. 244 private static HashMap _propertyMap; 245 246 static { 247 /////////////////////////////////////////////////////////// 248 // Actors that have properties that have changed class. 249 _classesWithParameterNameChanges = new HashMap<String, HashMap<String, String>>(); 250 251 // PNDirectory: After 2.2, 'Initial_queue_capacity' 252 // property is now 'initialQueueCapacity' 253 HashMap pnDirectorChanges = new HashMap<String, String>(); 254 255 // Key = property name, Value = new class name 256 pnDirectorChanges.put("Initial_queue_capacity", "initialQueueCapacity"); 257 _classesWithParameterNameChanges 258 .put("ptolemy.domains.pn.kernel.PNDirector", pnDirectorChanges); 259 260 // VariableDelay: After 4.0, 'defaultDelay' 261 // property is now 'delay' 262 HashMap variableDelayChanges = new HashMap<String, String>(); 263 variableDelayChanges.put("defaultDelay", "delay"); 264 _classesWithParameterNameChanges.put( 265 "ptolemy.domains.de.lib.VariableDelay", variableDelayChanges); 266 267 // Server: After 4.1, 'serviceTime' 268 // property is now 'newServiceTime' 269 // Regrettably, after 5.1, this reverted to serviceTime. 270 HashMap serverChanges = new HashMap<String, String>(); 271 serverChanges.put("newServiceTime", "serviceTime"); 272 _classesWithParameterNameChanges.put("ptolemy.domains.de.lib.Server", 273 serverChanges); 274 275 // CodeGenerator: After 7.2, 'generateJNI' 276 // property is now 'generateEmbeddedCode' 277 { 278 HashMap codegen = new HashMap<String, String>(); 279 codegen.put("generateJNI", "generateEmbeddedCode"); 280 _classesWithParameterNameChanges 281 .put("ptolemy.codegen.kernel.CodeGenerator", codegen); 282 } 283 { 284 HashMap codegen = new HashMap<String, String>(); 285 codegen.put("generateJNI", "generateEmbeddedCode"); 286 _classesWithParameterNameChanges.put( 287 "ptolemy.codegen.kernel.StaticSchedulingCodeGenerator", 288 codegen); 289 } 290 { 291 HashMap codegen = new HashMap<String, String>(); 292 codegen.put("generateJNI", "generateEmbeddedCode"); 293 _classesWithParameterNameChanges 294 .put("ptolemy.codegen.c.kernel.CCodeGenerator", codegen); 295 } 296 297 HashMap embeddedCodeActorChanges = new HashMap<String, String>(); 298 embeddedCodeActorChanges.put("embeddedCCode", "embeddedCode"); 299 _classesWithParameterNameChanges.put("ptolemy.cg.lib.EmbeddedCodeActor", 300 embeddedCodeActorChanges); 301 } 302}