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&lt;String, String&gt;();
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}