/* Filter to convert specific multiports of an actor to a single port. Copyright (c) 2004-2009 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.moml.filter; import java.util.HashMap; import java.util.Iterator; import ptolemy.kernel.util.NamedObj; import ptolemy.moml.MoMLFilter; import ptolemy.moml.MoMLParser; ////////////////////////////////////////////////////////////////////////// //// MultiportToSinglePort /** A filter to convert specific multiports of specific actors to a single ports. <p>When this class is registered with the MoMLParser.setMoMLFilter() method, it will cause will cause MoMLParser to filter so that models from earlier releases will run in the current release. <p>The Autocorrelation actor changed between PtolemyII 2.x and 3.x such that the output port is no longer a multiport. <pre> // Autocorrelation _actorsWithMultiPortToSinglePortChanges .put("ptolemy.actor.lib.Autocorrelation, "output") </pre> <p>The _actorsWithMultiPortToSinglePortChanges HashMap contains Strings that name classes such as Autocorrelation that have multiports that should be single ports. The HashMap maps classnames to port names. <p> Conceptually, how the code works is that when we see a class while parsing, we check to see if the class is in _actorsWithMultiPortToSinglePortChanges. If the class was present in the HashMap, then as we go through the code, we look for the named port and remove the multiport declaration @author Christopher Hylands Brooks, Contributor: Edward A. Lee @version $Id$ @since Ptolemy II 4.0 @Pt.ProposedRating Red (cxh) @Pt.AcceptedRating Red (cxh) */ public class MultiportToSinglePort implements MoMLFilter { /** If the attributeName is "class" and attributeValue names a * class that has had its port names changed between releases, * then substitute in the new port names. * * @param container The container for this attribute. * in this method. * @param element The XML element name. * @param attributeName The name of the attribute. * @param attributeValue The value of the attribute. * @param xmlFile The file currently being parsed. * @return the value of the attributeValue argument. */ public String filterAttributeValue(NamedObj container, String element, String attributeName, String attributeValue, String xmlFile) { //System.out.println("filterAttributeValue: " + container + "\t" // + attributeName + "\t" + attributeValue); // This method gets called many times by the MoMLParser, // so we try to be smart about the number of comparisons // and we try to group comparisons together so that we // are not making the same comparison more than once. if (attributeValue == null) { // attributeValue == null is fairly common, so we check for // that first return null; } if (attributeName.equals("name")) { // Save the name of the for later use if we see a "class" _lastNameSeen = attributeValue; if (_currentlyProcessingActorWithPropertyClassChanges) { if ((_portName != null) && _portName.equals(attributeValue)) { // We will do the above checks only if we found a // class that had property class changes. //_foundChange = true; } else { if (attributeValue.equals("multiport") && (container != null) && container.getName().equals(_portName)) { // What if the multiport is false? //_foundChange = false; MoMLParser.setModified(true); return null; } // Saw a name that did not match. // However, we might have other names that // did match, so keep looking //_foundChange = false; } } } // If you change this class, you should run before and after // timing tests on large moml files, a good command to run // is: // $PTII/bin/ptolemy -test $PTII/ptolemy/domains/ct/demo/CarTracking/CarTracking.xml // which will open up a large xml file and then close after 2 seconds. if (attributeName.equals("class")) { if (_actorsWithMultiPortToSinglePortChanges .containsKey(attributeValue)) { // We found a class with a property class change. _currentlyProcessingActorWithPropertyClassChanges = true; if (container == null) { // Under certain circumstances, we can parse something // that has no container _currentActorFullName = "." + _lastNameSeen; } else { _currentActorFullName = container.getFullName() + "." + _lastNameSeen; } _portName = (String) _actorsWithMultiPortToSinglePortChanges .get(attributeValue); // } else if (_currentlyProcessingActorWithPropertyClassChanges // && _foundChange) { // // We found a property class to change, and now we // // found the class itself that needs changing. // // Only return the new class once, but we might // // have other properties that need changing // //_currentlyProcessingActorWithPropertyClassChanges = false; // if (!attributeValue.equals(_newClass)) { // MoMLParser.setModified(true); // } // _foundChange = false; // return attributeValue; } else if (_currentlyProcessingActorWithPropertyClassChanges && (container != null) && !container.getFullName().equals(_currentActorFullName) && !container.getFullName().startsWith( _currentActorFullName)) { // We found another class in a different container // while handling a class with multiport change //_foundChange = false; _currentlyProcessingActorWithPropertyClassChanges = false; } } return attributeValue; } /** In this class, do nothing. * @param container The object created by this element. * @param elementName The element name. * @param currentCharData The character data, which appears * only in the doc and configure elements * @param xmlFile The file currently being parsed. * @exception Exception Not thrown in this base class. */ public void filterEndElement(NamedObj container, String elementName, StringBuffer currentCharData, String xmlFile) throws Exception { } /** Return a string that describes what the filter does. * @return the description of the filter that ends with a newline. */ public String toString() { StringBuffer results = new StringBuffer(getClass().getName() + ": Update any actor multiports that are now\n" + "single ports.\n" + "Below are the actors that are affected, along " + "with the port name:\n"); Iterator actors = _actorsWithMultiPortToSinglePortChanges.keySet() .iterator(); while (actors.hasNext()) { String actor = (String) actors.next(); results.append("\t" + actor + "\n" + (String) _actorsWithMultiPortToSinglePortChanges .get(actor)); } return results.toString(); } /////////////////////////////////////////////////////////////////// //// private variables //// // Map of actor names a HashMap of class names to multiport names // that should be single ports. private static HashMap _actorsWithMultiPortToSinglePortChanges; // The the full name of the actor we are currently processing private String _currentActorFullName; // Set to true if we are currently processing an actor with parameter // class changes, set to false when we are done. private boolean _currentlyProcessingActorWithPropertyClassChanges = false; // Last "name" value seen, for use if we see a "class". private String _lastNameSeen; // Keep track of whether a change was found. //private static boolean _foundChange; // The name of the port we are looking for. private String _portName; static { /////////////////////////////////////////////////////////// // Actors that have ports that have changed from multi to single _actorsWithMultiPortToSinglePortChanges = new HashMap(); // Autocorrelation _actorsWithMultiPortToSinglePortChanges.put( "ptolemy.domains.sdf.lib.Autocorrelation", "output"); _actorsWithMultiPortToSinglePortChanges.put( "ptolemy.actor.lib.NonStrictTest", "input"); // In Ptolemy II 3.0.2, SOC_FSM_SR_HDE.xml has a Const with multiport. _actorsWithMultiPortToSinglePortChanges.put("ptolemy.actor.lib.Const", "output"); _actorsWithMultiPortToSinglePortChanges.put( "ptolemy.actor.lib.gui.MatrixViewer", "input"); } }