Java tutorial
/* An actor with several sub-workflow choices for execution. * * Copyright (c) 2012 The Regents of the University of California. * All rights reserved. * * '$Author: crawl $' * '$Date: 2015-08-24 11:05:00 -0700 (Mon, 24 Aug 2015) $' * '$Revision: 33621 $' * * 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. * */ package org.kepler.ddp.actor; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.kepler.build.modules.Module; import org.kepler.build.modules.ModuleTree; //import org.kepler.ddp.gui.ExecutionChoiceEditorFactory; import org.kepler.ddp.gui.ExecutionChoiceEditorPane; import org.kepler.provenance.ProvenanceRecorder; import org.kepler.reporting.ReportingListener; import ptolemy.actor.IOPort; import ptolemy.actor.IOPortEvent; import ptolemy.actor.IOPortEventListener; import ptolemy.actor.TypedIOPort; import ptolemy.actor.gui.style.EditableChoiceStyle; import ptolemy.actor.lib.hoc.Case; import ptolemy.actor.lib.hoc.MultiCompositeActor; import ptolemy.actor.lib.hoc.MultiCompositePort; import ptolemy.actor.lib.hoc.Refinement; import ptolemy.data.BooleanToken; import ptolemy.data.StringToken; import ptolemy.data.Token; import ptolemy.data.expr.Parameter; import ptolemy.data.expr.StringParameter; import ptolemy.data.type.BaseType; import ptolemy.gui.ExtensionFilenameFilter; import ptolemy.kernel.ComponentEntity; import ptolemy.kernel.ComponentPort; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.Port; import ptolemy.kernel.Relation; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.ChangeListener; import ptolemy.kernel.util.ChangeRequest; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; import ptolemy.kernel.util.Settable; import ptolemy.kernel.util.SingletonAttribute; import ptolemy.kernel.util.Workspace; import ptolemy.moml.MoMLChangeRequest; import ptolemy.moml.MoMLParser; import ptolemy.util.CancelException; import ptolemy.util.MessageHandler; import ptolemy.vergil.basic.KeplerDocumentationAttribute; /** An actor that supports multiple choices for execution. Each choice * is a sub-workflow that can either be loaded from a set of templates, * or created by the user. * * Each file input port has an associated parameter. When an input token is read, * the associated parameter's value is set to the be token. * * Each file output also has an associated parameter. When the execution choice * finishes, the value of the parameter is written to the output port. * * @author Daniel Crawl * @version $Id: ExecutionChoice.java 33621 2015-08-24 18:05:00Z crawl $ * */ public class ExecutionChoice extends Case implements ChangeListener, IOPortEventListener { /** Create a new ExecutionChoice in a container with the * specified name. */ public ExecutionChoice(CompositeEntity container, String name) throws IllegalActionException, NameDuplicationException { super(container, name); _init(); } /** Create a new ExecutionChoice in a workspace. */ public ExecutionChoice(Workspace workspace) throws IllegalActionException, NameDuplicationException { super(workspace); _init(); } /** React to a change in an attribute. */ @Override public void attributeChanged(Attribute attribute) throws IllegalActionException { if (attribute == checkOutputTimestamp) { _checkOutputTimestampVal = ((BooleanToken) checkOutputTimestamp.getToken()).booleanValue(); } else if (attribute == control) { String newValue = ((StringToken) control.getToken()).stringValue(); // see if we've added the default choice if (_default != null && !newValue.equals(DEFAULT_TEMPLATE_NAME)) { // verify that the refinement exists boolean found = false; List<Refinement> refinements = entityList(Refinement.class); for (Refinement refinement : refinements) { if (refinement.getName().equals(newValue)) { found = true; break; } } if (!found) { throw new IllegalActionException(this, "Execution Choice '" + newValue + "' not found."); } } } else { super.attributeChanged(attribute); } } /** React to the fact that the change has been successfully executed * by doing nothing. * @param change The change that has been executed. */ @Override public void changeExecuted(ChangeRequest change) { // Nothing to do. } /** React to the fact that the change has failed by reporting it. * @param change The change that was attempted. * @param exception The exception that resulted. */ @Override public void changeFailed(ChangeRequest change, Exception exception) { // Ignore if this is not the originator. if ((change != null) && (change.getSource() != this)) { return; } if ((change != null) && !change.isErrorReported()) { change.setErrorReported(true); MessageHandler.error("Rename failed: ", exception); _changeRequestError = true; } } /** Override the base class to ensure that the member fields * are initialized. * @param workspace The workspace for the new object. * @return A new ExecutionChoice. * @exception CloneNotSupportedException If any of the attributes * cannot be cloned. */ @Override public Object clone(Workspace workspace) throws CloneNotSupportedException { ExecutionChoice newObject = (ExecutionChoice) super.clone(workspace); newObject._changeRequestError = false; newObject._checkOutputTimestampVal = true; newObject._choiceStyle = null; newObject._commandLineArguments = "$additionalOptions"; newObject._refinementCommandLines = new HashMap<Refinement, String>(); newObject._templateDir = null; return newObject; } /** Export an execution choice to a file. * @param saveFile the file to write the execution choice as a MoML XML. * @param name the name of the execution choice to save. */ public void exportExecutionChoice(File saveFile, String name) throws IllegalActionException, NameDuplicationException { final ComponentEntity<?> refinement = getEntity(name); if (refinement == null) { throw new IllegalActionException(this, "Execution choice " + name + " does not exist."); } // create the container to be exported. // it is a MultiCompositeActor because MultiCompositePorts cannot // be contained by other actors. final MultiCompositeActor toExport = new MultiCompositeActor(_workspace); toExport.setName(name); try { // copy ports to the workflow for (Port port : (List<Port>) portList()) { if (port != control.getPort()) { Port clonePort = (Port) port.clone(_workspace); clonePort.setContainer(toExport); // clone the File parameters if (getPortIOType(port) == IOType.File) { Parameter parameter = (Parameter) getAttribute(port.getName()); Parameter cloneParameter = (Parameter) parameter.clone(_workspace); cloneParameter.setContainer(toExport); } } } // copy parameters to the workflow for (String parameterName : getParameterNames()) { Parameter parameter = (Parameter) getAttribute(parameterName); Parameter cloneParameter = (Parameter) parameter.clone(_workspace); cloneParameter.setContainer(toExport); } // copy the refinement to the workflow Refinement cloneRefinement = (Refinement) refinement.clone(_workspace); cloneRefinement.setContainer(toExport); } catch (CloneNotSupportedException e) { throw new IllegalActionException(this, e, "Could not copy execution choice."); } // finally write out the workflow FileWriter writer = null; try { try { writer = new FileWriter(saveFile); toExport.exportMoML(writer); } finally { if (writer != null) { writer.close(); } } } catch (IOException e) { throw new IllegalActionException(this, e, "Error exporting to " + saveFile); } // delete the exported workflow from memory toExport.setContainer(null); } @Override public void fire() throws IllegalActionException { // if we're checking the last modified timestamps of output // files, save the current last modified timestamps before we // execute the template. final Map<String, Long> lastModifiedTimes = new HashMap<String, Long>(); if (_checkOutputTimestampVal) { for (String outputName : getOutputNames(false)) { StringParameter parameter = (StringParameter) getAttribute(outputName); String outputFileStr = parameter.stringValue(); File outputFile = new File(outputFileStr); lastModifiedTimes.put(outputFile.getPath(), outputFile.lastModified()); } } super.fire(); if (_checkOutputTimestampVal) { // verify that each output file's last modified timestamp // has increased. for (String outputName : getOutputNames(false)) { StringParameter parameter = (StringParameter) getAttribute(outputName); String outputFileStr = parameter.stringValue(); File outputFile = new File(outputFileStr); // do not check if the output is a directory if (!outputFile.isDirectory()) { long lastModifiedTimeBeforeExec = lastModifiedTimes.get(outputFile.getPath()); // see if the file was not updated if (lastModifiedTimeBeforeExec > 0 && outputFile.lastModified() <= lastModifiedTimeBeforeExec) { throw new IllegalActionException(this, "Output " + outputName + " (" + outputFile + ")\n" + "does not appear to have been updated."); } // see if the file did not exist before and after we executed the refinement else if (outputFile.lastModified() == 0) { throw new IllegalActionException(this, "Output " + outputName + " (" + outputFile + ")\n" + " was not created."); } } } } } /** Get the command line argument for a parameter. * @param name the name of the parameter * @return the command line argument if one was set, otherwise null */ public String getArgument(String name) throws IllegalActionException { return getArgument(this, name); } /** Get the command line argument for a parameter in a specific container * @param container the container * @param name the name of the parameter * @return the command line argument if one was set, otherwise null */ public static String getArgument(NamedObj container, String name) throws IllegalActionException { Parameter argumentParameter = getArgumentParameter(container, name); if (argumentParameter != null) { return argumentParameter.getExpression(); } return null; } /** Get the parameter containing the command line argument for a parameter. * @param name the name of the parameter * @return the parameter containing the value of the argument */ public StringParameter getArgumentParameter(String name) throws IllegalActionException { return getArgumentParameter(this, name); } /** Get the parameter containing the command line argument for a parameter * in a specific container. * @param container the container * @param name the name of the parameter * @return the parameter containing the value of the argument */ public static StringParameter getArgumentParameter(NamedObj container, String name) throws IllegalActionException { Attribute attribute = container.getAttribute(name); if (attribute == null) { throw new IllegalActionException(container, "No component with name " + name); } return (StringParameter) attribute.getAttribute(ARGUMENT_NAME); } /** Get a list of execution choice names. */ public List<String> getExecutionChoiceNames() { final List<Refinement> refinements = entityList(Refinement.class); final String[] namesArray = new String[refinements.size()]; int i = 0; for (Refinement refinement : refinements) { namesArray[i++] = refinement.getName(); } Arrays.sort(namesArray); return Arrays.asList(namesArray); } /** Get a list of file input names. */ public List<String> getInputNames() throws IllegalActionException { return getInputNames(false); } /** Get a list of input port names. */ public List<String> getInputNames(boolean includeData) throws IllegalActionException { return _getIONames(inputPortList(), includeData); } /** Get a list of file output names. */ public List<String> getOutputNames() throws IllegalActionException { return getOutputNames(false); } /** Get a list of output port names. */ public List<String> getOutputNames(boolean includeData) throws IllegalActionException { return _getIONames(outputPortList(), includeData); } /** Get a list of parameter names. The returned list does not include * parameters associated with inputs or outputs, fields of * ExecutionChoice, visibility set to none, or names starting with "_". */ public List<String> getParameterNames() throws IllegalActionException { final List<String> inputs = getInputNames(false); final List<String> outputs = getOutputNames(false); final List<String> fields = new LinkedList<String>(); for (Field field : getClass().getFields()) { fields.add(field.getName()); } final List<String> parameterNames = new LinkedList<String>(); for (Parameter parameter : attributeList(Parameter.class)) { String name = parameter.getName(); if (!inputs.contains(name) && !outputs.contains(name) && !fields.contains(name) && !name.startsWith("_") && parameter.getVisibility() != Settable.NONE) { parameterNames.add(name); } } return parameterNames; } /** Get the parameter type for a parameter. */ public ParameterType getParameterType(String name) throws IllegalActionException { return getParameterType(this, name); } /** Get the parameter type for a parameter in a container within this actor. */ public static ParameterType getParameterType(NamedObj container, String name) throws IllegalActionException { Parameter parameter = (Parameter) container.getAttribute(name); if (parameter == null) { throw new IllegalActionException(container, "Parameter " + name + " in " + container.getName() + " not found."); } if (parameter instanceof StringParameter) { return ParameterType.String; } else { return ParameterType.Numeric; } } /** Get the IOType for a port. */ public static IOType getPortIOType(Port port) throws IllegalActionException { Parameter typeParameter = (Parameter) port.getAttribute(IO_TYPE_NAME); if (typeParameter == null) { System.err.println("WARNING: missing IO type for " + port + "."); System.err.println("Assuming type is File."); try { _setPortIOTypeParameter(port, IOType.File); } catch (NameDuplicationException e) { throw new IllegalActionException(port, e, "Error setting Port IO type."); } return IOType.File; } return IOType.valueOf(typeParameter.getExpression()); } /** Get the available template names. */ public Set<String> getTemplateNames() throws IllegalActionException { String[] files = _templateDir.list(new ExtensionFilenameFilter("xml")); String[] names = new String[files.length + 1]; // remove the extensions for (int i = 0; i < files.length; i++) { names[i] = files[i].substring(0, files[i].length() - 4); } // add choice for an empty refinement names[files.length] = EMPTY_TEMPLATE_NAME; Arrays.sort(names); return new LinkedHashSet<String>(Arrays.asList(names)); } /** Returns true if there is an input with the given name. */ public boolean hasInput(String name) { return _hasInputOutput(name, true); } /** Returns true if there is an output with the given name. */ public boolean hasOutput(String name) { return _hasInputOutput(name, false); } /** Create a new execution choice from a template. * @param templateName the name of the template. The * template name must be contained in the set of names * return by getTemplateNames(). * @param name the name to give the new refinement * @return The refinement created for the new execution choice. */ public Refinement newExecutionChoice(String templateName, String refinementName) throws IllegalActionException { Refinement newRefinement = null; if (templateName.equals(EMPTY_TEMPLATE_NAME)) { try { newRefinement = newRefinement(refinementName); // add ports to the blank refinement _updatePortsAndInsideLinks(); updateExecutionChoices(); _addCommandLineParameter(newRefinement); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding blank template."); } } else { String templateNameReplaced = templateName.replaceAll(" ", ""); File templateFile = new File(_templateDir, templateNameReplaced + ".xml"); if (!templateFile.exists()) { throw new IllegalActionException(this, "Could not find template " + templateName + ": " + templateFile); } newRefinement = newExecutionChoice(templateFile, refinementName); } return newRefinement; } /** Create a new execution choice from a file. * @param templateFile the containing the MoML of the execution choice. * @param name the name to give the new refinement. * @return The refinement created for the new execution choice. */ public Refinement newExecutionChoice(File templateFile, String refinementName) throws IllegalActionException { // see if a refinement with the same name already exists Refinement existingRefinement = (Refinement) getEntity(refinementName); if (existingRefinement != null) { // in some cases, the default local execution refinement is saved // in the model. if the existing refinement is the default one, // rename it. if (refinementName.equals(DEFAULT_TEMPLATE_NAME)) { try { existingRefinement.setName("OLD " + DEFAULT_TEMPLATE_NAME); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Unable to rename " + " old LocalExecution execution choice."); } } else { throw new IllegalActionException(this, "An execution choice with the name " + refinementName + " has already been loaded."); } } //final List<Refinement> existingRefinements = entityList(Refinement.class); Refinement newRefinement = null; ExecutionChoice container = null; try { container = new ExecutionChoice(_workspace); container.setName("imported container"); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error create new MultiCompositeActor."); } // add program and additionalOptions parameters to the container // since parameters in the template may reference them /* try { new StringParameter(container, "program"); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error creating program parameter."); } try { new StringParameter(container, "additionalOptions"); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error creating additionalOptions parameter."); } */ try { addDefaultInputsAndOutputs(container); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding defaults to container."); } // call validateSettables() to validate program and additionalOptions //container.validateSettables(); // load the template file into the container _loadExecutionChoice(templateFile, container); MultiCompositeActor exportedContainer; // see if the template was a refinement (old version) if (container.entityList(MultiCompositeActor.class).isEmpty()) { System.out .println("WARNING: template is older version that does " + "not contain ports and parameters."); exportedContainer = container; } else { exportedContainer = container.entityList(MultiCompositeActor.class).get(0); // create ports for (Port port : (List<Port>) exportedContainer.portList()) { // see if we already have a port with this name final String portName = port.getName(); if (getPort(portName) == null) { final IOType type = getPortIOType(port); // if it's a File, get the argument String argument = null; if (type == IOType.File) { argument = getArgument(exportedContainer, portName); } try { if (((IOPort) port).isInput()) { newInput(portName, type, argument); } else { newOutput(portName, type, argument); } } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error creating port " + portName + " from template."); } // if it's a File, set the parameter value String value = ((Parameter) exportedContainer.getAttribute(portName)).getExpression(); ((Parameter) getAttribute(portName)).setExpression(value); } } // create parameters List<Parameter> parameterList = new LinkedList<Parameter>( exportedContainer.attributeList(Parameter.class)); for (Parameter parameter : parameterList) { final String parameterName = parameter.getName(); // see if we already have a parameter with this name, or // the parameter was created when we added ports above if (getAttribute(parameterName) == null) { try { parameter.setContainer(this); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding port " + parameterName + " from template."); } } } } // move the refinement List<Refinement> refinements = exportedContainer.entityList(Refinement.class); if (refinements.size() == 0) { throw new IllegalActionException(this, "No execution choices found in template."); } newRefinement = refinements.get(0); if (refinements.size() > 1) { System.out.println("WARNING: more than one executon choice found in template."); System.out.println("Only " + newRefinement.getName() + " will be loaded."); } try { // set the name before moving the refinement to this actor newRefinement.setName(refinementName); newRefinement.setContainer(this); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding template into actor."); } try { container.setContainer(null); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error deleting template container."); } // the template is the new refinement /* final List<Refinement> currentRefinements = entityList(Refinement.class); for(Refinement refinement : currentRefinements) { if(!existingRefinements.contains(refinement)) { newRefinement = refinement; break; } } if(newRefinement == null) { throw new IllegalActionException(this, "Error loading refinement." + " Perhaps it is not a Refinement?"); } */ /* if(!(newRefinement instanceof Refinement)) { throw new IllegalActionException(this, "Template is not a Refinement."); } */ // we no longer have to clone the refinement into our workspace since // the template is loaded by incremental parsing. /* try { newRefinement = (Refinement) namedObj.clone(workspace()); } catch (CloneNotSupportedException e) { throw new IllegalActionException(this, e, "Cloning error."); } */ // remove provenance recorder and reporting listener // if they are present List<Attribute> toRemove = new LinkedList<Attribute>(newRefinement.attributeList(ProvenanceRecorder.class)); toRemove.addAll(newRefinement.attributeList(ReportingListener.class)); for (Attribute attribute : toRemove) { try { attribute.setContainer(null); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error removing " + attribute.getName()); } } try { newRefinement.setContainer(this); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding template."); } // NOTE: do not update _current, since that's done in CaseDirector.prefire(). if (_default == null) { _default = newRefinement; } // the refinement loaded from the template and the containing // MultiCompositeActor (this class) may have a different set // of ports. we need to make sure they both have the same set // of ports and each outside-inside pair are linked. // FIXME is this still necessary? _updatePortsAndInsideLinks(); updateExecutionChoices(); _addCommandLineParameter(newRefinement); // repaint the canvas to show new ports MoMLChangeRequest change = new MoMLChangeRequest(this, this, "<group></group>"); change.setPersistent(false); requestChange(change); return newRefinement; } private void _loadExecutionChoice(File templateFile, NamedObj container) throws IllegalActionException { MoMLParser parser = new MoMLParser(); // NOTE: the template may reference parameters not defined in the // template but defined in ExecutionChoice, e.g., outputPath or // inputPath, so we set the parser's context to this actor to // avoid exceptions when parsing the template. parser.setContext(container); String templateStr = null; try { templateStr = FileUtils.readFileToString(templateFile); } catch (IOException e) { throw new IllegalActionException(this, e, "Error reading template file " + templateFile.getAbsolutePath()); } try { // use incremental parsing to load the template. // this is necessary since all the MoMLParser.parse() // methods return the top-level object, which is our // top-level object since we called MoMLParser.setContext(). // don't put in a <group></group> since the template MoML is // a top-level object (contains <!DOCTYPE> //StringBuilder moml = new StringBuilder("<group>"); //moml.append(templateStr); //moml.append("</group>"); //parser.parse(moml.toString()); parser.parse(templateStr); } catch (Exception e) { throw new IllegalActionException(this, e, "Error parsing " + templateFile); } } /** Create a new file input. */ public void newInput(String name, IOType type) throws NameDuplicationException, IllegalActionException { newInput(name, type, null); } /** Create a new file input. */ public void newInput(String name, IOType type, String argument) throws NameDuplicationException, IllegalActionException { _newInputOrOutput(name, type, argument, true); // if the IO type is file, and the name is not the default // input directory name, set the default value of the // parameter to be the default input directory . the name if (type == IOType.File && !name.equals(DEFAULT_INPUT_DIR_NAME)) { Parameter parameter = (Parameter) getAttribute(name); if (getAttribute(DEFAULT_INPUT_DIR_NAME) != null) { parameter.setExpression("$" + DEFAULT_INPUT_DIR_NAME + File.separator + getName() + "." + name); } else { parameter.setExpression(getName() + "." + name); } } /* NOTE: PortParameter ports are not mirrored for MultiCompositeActors PortParameter input = new PortParameter(this, name); input.setStringMode(true); input.setExpression(getName() + "." + name); TypedIOPort port = input.getPort(); port.setTypeEquals(BaseType.STRING); new SingletonAttribute(port, "_showName"); */ } /** Create a new file output. */ public void newOutput(String name, IOType type) throws IllegalActionException, NameDuplicationException { newOutput(name, type, null); } /** Create a new file output. */ public void newOutput(String name, IOType type, String argument) throws IllegalActionException, NameDuplicationException { _newInputOrOutput(name, type, argument, false); // if the IO type is file, and the name is not the default // output directory name, set the default value of the // parameter to be the default output directory . the name if (type == IOType.File && !name.equals(DEFAULT_OUTPUT_DIR_NAME)) { Parameter parameter = (Parameter) getAttribute(name); if (getAttribute(DEFAULT_OUTPUT_DIR_NAME) != null) { parameter.setExpression("$" + DEFAULT_OUTPUT_DIR_NAME + File.separator + getName() + "." + name); } else { parameter.setExpression(getName() + "." + name); } } } /** Add a new parameter. * @param name the parameter name * @param argument the command line argument for this parameter. this can be null. */ public void newParameter(String name, String argument) throws IllegalActionException, NameDuplicationException { newParameter(name, argument, null); } /** Add a new parameter. * @param name the parameter name * @param argument the command line argument for this parameter. this can be null. * @param value the default value for the paramete. this can be null. */ public void newParameter(String name, String argument, String value) throws IllegalActionException, NameDuplicationException { newParameter(name, argument, value, null, ParameterType.String); } /** Add a new parameter. * @param name the parameter name * @param argument the command line argument for this parameter. this can be null. * @param value the default value for the paramete. this can be null. * @param choice the refinement in which to add the parameter. if null or * set to ALL_CHOICES_NAME, the parameter is added to this actor. */ public void newParameter(String name, String argument, String value, String choice, ParameterType type) throws IllegalActionException, NameDuplicationException { ComponentEntity<?> refinement = null; if (choice != null && !choice.equals(ALL_CHOICES_NAME)) { refinement = getEntity(choice); } NamedObj container; if (refinement == null) { container = this; } else { container = refinement; } Parameter parameter; if (type == ParameterType.Numeric) { parameter = new Parameter(container, name); } else { parameter = new StringParameter(container, name); } if (argument != null && !argument.isEmpty()) { setArgument(parameter, argument); } if (value != null) { parameter.setExpression(value); } if (refinement == null) { _addToCommandLines(name); } } /** Create a new execution choice. Override the parent class to * add the execution choice name to the parameter list. */ /* @Override public Refinement newRefinement(String name) throws IllegalActionException, NameDuplicationException { Refinement refinement = super.newRefinement(name); if(!name.equals("default")) { control.addChoice(name); } return refinement; } */ /** Receive a port event. If the port is an input port and has an * associated parameter, set the value of the parameter to be * the token read by the port. */ @Override public void portEvent(IOPortEvent event) throws IllegalActionException { //System.out.println(event); if (event.getEventType() == IOPortEvent.GET_END) { //System.out.println("got read: " + event); IOPort port = event.getPort(); StringParameter parameter = (StringParameter) getAttribute(port.getName()); if (parameter != null) { parameter.setToken(event.getToken()); //System.out.println("set parameter " + parameter); } } } /** List to port events for File input ports so that when a token is read, we * can set the corresponding parameter. Also, make sure output Data file ports * that are connected outside are connected in the current refinement. * * @see #portEvent() */ @Override public void preinitialize() throws IllegalActionException { super.preinitialize(); addDefaultExecutionChoice(); for (Object object : portList()) { final TypedIOPort port = (TypedIOPort) object; // see if the IOType is file if (port != control.getPort() && getPortIOType(port) == IOType.File) { // for input ports, listen to port events so we can set // the corresponding parameter if (port.isInput()) { port.addIOPortEventListener(this); } // set the type to string port.setTypeEquals(BaseType.STRING); } // make sure output data ports that are connected outside, are connected // inside the current refinement if (port.isOutput() && port.numberOfSinks() > 0) { final IOType type = getPortIOType(port); if (type == IOType.Data) { // make sure it's connected inside String refinementName = ((StringToken) control.getToken()).stringValue(); Refinement refinement = (Refinement) getEntity(refinementName); if (refinement == null) { throw new IllegalActionException(this, "Execution choice not found: " + refinementName); } IOPort refinementPort = (IOPort) refinement.getPort(port.getName()); if (!refinementPort.isInsideConnected()) { throw new IllegalActionException(this, "Output Data port " + port.getName() + " is not connected inside the execution choice " + refinementName); } } } } // create directories for File outputs for (String outputName : getOutputNames(false)) { // create directories for outputs with specific names if (outputName.endsWith("Dir") || outputName.endsWith("_dir") || outputName.endsWith("_Dir")) { Parameter outputParameter = (Parameter) getAttribute(outputName); if (outputParameter != null) { Token token = outputParameter.getToken(); if (token != null) { String outputString; if (token instanceof StringToken) { outputString = ((StringToken) token).stringValue(); } else { outputString = token.toString(); } // make sure the value is not empty if (!outputString.trim().isEmpty()) { File outputPathDir = new File(outputString); if (!outputPathDir.exists() && !outputPathDir.mkdirs()) { throw new IllegalActionException(this, "Could not create " + " directory: " + outputPathDir); } } } } } } } /** Remove an execution choice. */ public void removeExecutionChoice(String name) throws IllegalActionException, NameDuplicationException { ComponentEntity<?> refinement = getEntity(name); if (refinement == null) { throw new IllegalActionException(this, "Could not find execution choice " + name); } refinement.setContainer(null); // update the choices in the control parameter updateExecutionChoices(); } /** Remove a file input. */ public void removeInput(String name) throws Exception { _removeInputOrOutput(name, true); } /** Remove a file output. */ public void removeOutput(String name) throws Exception { _removeInputOrOutput(name, false); } /** Remove a parameter. */ public void removeParameter(String name) throws Exception { Attribute attribute = getAttribute(name); if (attribute == null) { throw new IllegalActionException(this, "No parameter called " + name); } // remove first from command line since we know the argument, if any _removeFromCommandLines(name); // remove from any parameters that are referencing it _removeFromIOParameters(name); attribute.setContainer(null); _removeInDocumentation(name); } /** Rename an execution choice. */ public void renameExecutionChoice(String oldName, String newName) { //System.out.println("rename choice " + oldName + " to " + newName); _rename("entity", oldName, newName, null, this); } /** Rename an input. */ public void renameInput(String oldName, String newName) { _renameInputOrOutput(oldName, newName, true); } /** Rename a parameter. */ public boolean renameParameter(String oldName, String newName) { return renameParameter(oldName, newName, this); } /** Rename a parameter in the specified container. */ public boolean renameParameter(String oldName, String newName, NamedObj container) { //System.out.println("rename parameter " + oldName + " to " + newName); boolean retval = false; if (container == this) { // save the command lines and clear them since rename is broken _saveAndClearCommandLines(); } // do the rename boolean renamed = _rename("property", oldName, newName, null, container); if (container == this) { // see if the renamed failed if (!renamed) { // restore the command lines to their original values _restoreCommandLines(); } else { // update the command lines with the parameter renamed _renameInCommandLines(oldName, newName); // update the documentation try { _renameInDocumentation(oldName, newName); } catch (Exception e) { try { MessageHandler.warning("Unable to update documentation.", e); } catch (CancelException e1) { // ignore } } retval = true; } } return retval; } /** Rename an output. */ public void renameOutput(String oldName, String newName) { _renameInputOrOutput(oldName, newName, false); } /** Set the command line argument for a parameter. */ public static void setArgument(Parameter parameter, String argument) throws IllegalActionException, NameDuplicationException { StringParameter argumentParameter = (StringParameter) parameter.getAttribute(ARGUMENT_NAME); if (argumentParameter == null) { argumentParameter = new StringParameter(parameter, ARGUMENT_NAME); } argumentParameter.setExpression(argument); } /** Set the ParameterType for a parameter contained by this actor. */ public void setParameterType(String name, ParameterType type) throws IllegalActionException, NameDuplicationException { setParameterType(this, name, type); } /** Set the ParameterType for a parameter in contained in a sub-workflow. */ public static void setParameterType(NamedObj container, String name, ParameterType type) throws IllegalActionException, NameDuplicationException { Parameter parameter = (Parameter) container.getAttribute(name); if (parameter == null) { throw new IllegalActionException(container, "Parameter " + name + " in " + container.getName() + " not found."); } // save the current value and argument final String value = parameter.getExpression(); final String argument = getArgument(container, name); // FIXME this can bring up the warning about dependencies parameter.setContainer(null); if (type == ParameterType.String) { parameter = new StringParameter(container, name); } else { parameter = new Parameter(container, name); } // restore the current value and argument // XXX what happens if value is a string and the type is numeric? parameter.setExpression(value); if (argument != null) { setArgument(parameter, argument); } } /** Set the PortType for a port. */ public void setPortIOType(TypedIOPort port, IOType type) throws IllegalActionException, NameDuplicationException { final String portName = port.getName(); _setPortIOTypeParameter(port, type); if (type == IOType.File) { port.setTypeEquals(BaseType.STRING); // create the associated parameter /*StringParameter newParameter =*/ new StringParameter(this, portName); _addToCommandLines(portName); } else { // type == IOType.Data port.setTypeEquals(BaseType.UNKNOWN); // remove the parameter from the command lines. // NOTE: this is done before removing the parameter since it // accessed the parameter argument. _removeFromCommandLines(portName); // remove the name if referenced in any other parameter _removeFromIOParameters(portName); // remove the associated parameter and any argument StringParameter associatedParameter = (StringParameter) getAttribute(portName); // FIXME this can display the warning dialog about dependencies associatedParameter.setContainer(null); } _updatePortsAndInsideLinks(); } /** Update the execution choices in the control parameter. */ public void updateExecutionChoices() throws IllegalActionException { List<String> choices = new LinkedList<String>(); List<StringParameter> existingChoices = _choiceStyle.attributeList(StringParameter.class); for (StringParameter parameter : existingChoices) { if (parameter.getName().startsWith("choice")) { String name = parameter.getExpression(); // make sure refinement exists if (getEntity(name) == null) { try { // refinement no longer exists so remove the choice parameter.setContainer(null); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error removing choice " + name); } } else { choices.add(name); } } } for (Refinement refinement : entityList(Refinement.class)) { if (!choices.contains(refinement.getDisplayName())) { // add a new parameter contained by the choice style so that the // choice is saved to MoML. Parameter choiceParameter; try { choiceParameter = new StringParameter(_choiceStyle, _choiceStyle.uniqueName("choice")); choiceParameter.setExpression(refinement.getDisplayName()); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding choice."); } choices.add(refinement.getDisplayName()); } } // see if current choice was removed if (!choices.isEmpty() && !choices.contains(((StringToken) control.getToken()).stringValue())) { // set the control choice to the default control.setExpression(choices.get(0)); } } /** Perform cleanup. Stop listening to input ports. */ @Override public void wrapup() throws IllegalActionException { super.wrapup(); for (Object object : inputPortList()) { IOPort port = (IOPort) object; if (getAttribute(port.getName()) != null) { port.removeIOPortEventListener(this); } } } /** The command line program to execute. */ public StringParameter program; /** Additional command line options. */ public StringParameter additionalOptions; /** If true, verify the last modification timestamp for each * output file has increased after execution. If the timestamp * has not increased, throw an error. */ public Parameter checkOutputTimestamp; /** The name of the default template. */ public final static String DEFAULT_TEMPLATE_NAME = "LocalExecution"; /** The name of the default input directory. */ public final static String DEFAULT_INPUT_DIR_NAME = "inputDir"; /** The name of the default output directory. */ public final static String DEFAULT_OUTPUT_DIR_NAME = "outputDir"; /** The name of the default input file. */ public final static String DEFAULT_INPUT_FILE_NAME = "inputFile"; /** The name of the default output file. */ public final static String DEFAULT_OUTPUT_FILE_NAME = "outputFile"; /** String constant to denote all execution choices. **/ public final static String ALL_CHOICES_NAME = "All Choices"; /** The name of the (optional) attribute contained in parameters. * The value of this attribute is the command-line argument for * the parameter, e.g., "-e". */ public final static String ARGUMENT_NAME = "Argument"; /** The name of the command line parameter in each refinement. */ public final static String COMMAND_LINE_NAME = "commandLine"; /** The types of input/outputs. */ public enum IOType { File, Data; }; /** The types of parameters. */ public enum ParameterType { Numeric, String; } /////////////////////////////////////////////////////////////////// //// protected methods //// /** Create a director. This base class creates an instance of CaseDirector. * @return The created director. * @exception IllegalActionException If the director cannot be created. * @exception NameDuplicationException If there is already an * attribute with the name "_director". */ @Override protected ExecutionChoiceDirector _createDirector() throws IllegalActionException, NameDuplicationException { return new ExecutionChoiceDirector(this, "_director"); } /** Set the refinement to execute. */ protected void _setCurrentRefinement(Refinement refinement) { _current = refinement; } /////////////////////////////////////////////////////////////////// //// private method //// /** Add a input/output/parameter to the command lines of each refinement. */ private void _addToCommandLines(String name) throws IllegalActionException, NameDuplicationException { // construct the string to add String toAdd = _makeCommandLineArgument(name); // see if we should add to beginning or end String argument = getArgument(name); boolean append = (argument != null && argument.equals(">")); // update each refinement for (Refinement refinement : entityList(Refinement.class)) { Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); if (commandLineParameter == null) { commandLineParameter = new StringParameter(refinement, COMMAND_LINE_NAME); //commandLineParameter.setLazy(true); } String expression = commandLineParameter.getExpression(); if (append) { commandLineParameter.setExpression(expression + " " + toAdd); } else { // add to the beginning of the command line, but after $program int index = expression.indexOf("$program"); // make sure $program was found; otherwise do not add if (index > -1) { // if expression is only "$program", add a space and the argument to add if (expression.equals("$program")) { commandLineParameter.setExpression("$program " + toAdd + " "); } else { StringBuilder value = new StringBuilder(expression); value.insert(index + "$program".length() + 1, toAdd + " "); commandLineParameter.setExpression(value.toString()); } } } //System.out.println("add: new command line for " + refinement.getName() + ":" + //commandLineParameter.getExpression()); } // update the default command line if (append) { _commandLineArguments += " " + toAdd; } else { _commandLineArguments = toAdd + " " + _commandLineArguments; } } /** Add the commandLine parameter to a refinement if it is not there. */ private void _addCommandLineParameter(Refinement refinement) throws IllegalActionException { // see if the commandLine parameter exists in this refinement Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); if (commandLineParameter == null) { try { commandLineParameter = new StringParameter(refinement, COMMAND_LINE_NAME); //commandLineParameter.setLazy(true); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding commandLine parameter."); } // set the default value commandLineParameter.setExpression("$program " + _commandLineArguments); } } /** Get a list of input/output names. * @param ports the input or output ports from which to get names. * @param includeData if true, include Data ports in the list of names. * otherwise, just return a list of File ports. */ private List<String> _getIONames(List<?> ports, boolean includeData) throws IllegalActionException { final List<String> retval = new LinkedList<String>(); for (Object object : ports) { if (object != control.getPort()) { final TypedIOPort port = (TypedIOPort) object; if (includeData || getPortIOType(port) == IOType.File) { retval.add(port.getDisplayName()); } /* if(getAttribute(port.getDisplayName()) != null) { retval.add(port.getDisplayName()); } */ } } return retval; } /** Returns true if there is an input/output with the given name. * @param name The name to check. * @param input If true, check inputs, otherwise check outputs. * @return True if the input/output exists. */ private boolean _hasInputOutput(String name, boolean input) { TypedIOPort port = (TypedIOPort) getPort(name); if (port != null) { if (input) { return port.isInput(); } else { return port.isOutput(); } } return false; } /** Initialize parameters and load the default template. */ private void _init() throws NameDuplicationException, IllegalActionException { setClassName("org.kepler.ddp.actor.ExecutionChoice"); // remove the default refinement created by the parent class _default.setContainer(null); _default = null; // hide the control port control.setStringMode(true); new SingletonAttribute(control.getPort(), "_hide"); control.setDisplayName("Choice"); control.setExpression(DEFAULT_TEMPLATE_NAME); control.removeAllChoices(); program = new StringParameter(this, "program"); program.setExpression("ls"); additionalOptions = new StringParameter(this, "additionalOptions"); //new ExecutionChoiceEditorFactory(this, "_editor"); new ExecutionChoiceEditorPane.Factory(this, "_editorPane"); _choiceStyle = new EditableChoiceStyle(control, "style"); // parse the template ModuleTree tree = ModuleTree.instance(); Module module = tree.getModuleByStemName("ddp-common"); if (module == null) { throw new IllegalActionException(this, "Could not find ddp-common module in suite."); } String templateDirPathStr = module.getResourcesDir().getAbsolutePath() + File.separator + "templates" + File.separator + "ExecutionChoice"; _templateDir = new File(templateDirPathStr); checkOutputTimestamp = new Parameter(this, "checkOutputTimestamp"); checkOutputTimestamp.setTypeEquals(BaseType.BOOLEAN); checkOutputTimestamp.setToken(BooleanToken.TRUE); } public void addDefaults() throws IllegalActionException, NameDuplicationException { addDefaultInputsAndOutputs(); addDefaultExecutionChoice(); } /** Add default execution choice if none are present. */ public void addDefaultExecutionChoice() throws IllegalActionException { // see if there are any execution choices if (getExecutionChoiceNames().isEmpty()) { // load the default newExecutionChoice(DEFAULT_TEMPLATE_NAME, DEFAULT_TEMPLATE_NAME); } } /** Add default inputs and outputs if none are present. * @return true if inputs/outputs were created. */ public boolean addDefaultInputsAndOutputs() throws NameDuplicationException, IllegalActionException { return addDefaultInputsAndOutputs(this); } /** Add default inputs and outputs if non are present for an ExecutionChoice. * @return true if inputs/outputs were created. */ public static boolean addDefaultInputsAndOutputs(ExecutionChoice choice) throws IllegalActionException, NameDuplicationException { // see if there are any inputs or outputs if (choice.getInputNames(true).isEmpty() && choice.getOutputNames(true).isEmpty()) { System.out.println("Adding default inputs, outputs for " + choice.getName()); choice.newInput(DEFAULT_INPUT_FILE_NAME, IOType.File, "-i"); choice.newOutput(DEFAULT_OUTPUT_FILE_NAME, IOType.File, ">"); choice.newInput(DEFAULT_INPUT_DIR_NAME, IOType.File, "-i"); choice.newOutput(DEFAULT_OUTPUT_DIR_NAME, IOType.File, ">"); // repaint the canvas to show new ports MoMLChangeRequest change = new MoMLChangeRequest(choice, choice, "<group></group>"); change.setPersistent(false); choice.requestChange(change); return true; } return false; } /** Get the command line string for an input/output/parameter. */ private String _makeCommandLineArgument(String name) throws IllegalActionException { // construct the string to add to the command lines StringBuilder str = new StringBuilder(); // see if there's a argument String argument = getArgument(name); if (argument != null) { str.append("$("); str.append(name); str.append("::"); str.append(ARGUMENT_NAME); str.append(") "); } // add the name str.append("$"); str.append(name); return str.toString(); } /** Create a new port and parameter for a new input or output. * @param name the name of the input/output * @param type the IOType of the input/output * @param argument the command line argument for the new input * or output. this is only valid for IOType.File inputs/outputs, * and can be null. * @param isInput if true, the port is an input port. if false, the * ports is an output port. */ private void _newInputOrOutput(String name, IOType type, String argument, boolean isInput) throws IllegalActionException, NameDuplicationException { if (type != IOType.File && argument != null && !argument.isEmpty()) { throw new IllegalActionException(this, "Command-line arguments can only be " + "specified for File types."); } TypedIOPort port = (TypedIOPort) newPort(name); new SingletonAttribute(port, "_showName"); // set the port to be input or output // NOTE: this must be done before _showOrHideInsidePort() is called // (in _updatePortsAndInsideLinks()) since it hides outputs ports. if (isInput) { port.setInput(true); } else { port.setOutput(true); } _setPortIOTypeParameter(port, type); if (type == IOType.File) { port.setTypeEquals(BaseType.STRING); // create the associated parameter StringParameter newOutputParameter = new StringParameter(this, name); if (argument != null && !argument.isEmpty()) { setArgument(newOutputParameter, argument); } _addToCommandLines(name); } _updatePortsAndInsideLinks(); } /** Remove a input/output/parameter from the refinement command lines.*/ private void _removeFromCommandLines(String name) throws IllegalActionException, NameDuplicationException { // construct the string to remove String toRemove = _makeCommandLineArgument(name); for (Refinement refinement : entityList(Refinement.class)) { Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); if (commandLineParameter == null) { commandLineParameter = new StringParameter(refinement, COMMAND_LINE_NAME); //commandLineParameter.setLazy(true); } String expression = commandLineParameter.getExpression(); int index = expression.indexOf(toRemove); if (index > -1) { String value = expression.substring(0, index) + expression.substring(index + toRemove.length()); commandLineParameter.setExpression(value.trim()); commandLineParameter.validate(); } //System.out.println("remove: new command line for " + refinement.getName() + ":" + //commandLineParameter.getExpression()); } // remove form the default command line int index = _commandLineArguments.indexOf(toRemove); if (index > -1) { String value = _commandLineArguments.substring(0, index) + _commandLineArguments.substring(index + toRemove.length()); _commandLineArguments = value.trim(); } } /** Remove a name that is referenced in any input/output parameters. */ private void _removeFromIOParameters(String name) throws IllegalActionException { String toRemove = "$" + name; List<String> toCheck = new LinkedList<String>(); toCheck.addAll(getInputNames(false)); toCheck.addAll(getOutputNames(false)); for (String toCheckName : toCheck) { boolean changed = false; Parameter parameter = (Parameter) getAttribute(toCheckName); String expression = parameter.getExpression(); int index = expression.indexOf(toRemove); while (index > -1) { changed = true; expression = expression.substring(0, index) + expression.substring(index + toRemove.length()); index = expression.indexOf(toRemove); } if (changed) { parameter.setExpression(expression.trim()); parameter.validate(); } } } /** Remove a port or parameter from the documentation. */ private void _removeInDocumentation(String name) throws Exception { List<KeplerDocumentationAttribute> docList = attributeList(KeplerDocumentationAttribute.class); for (KeplerDocumentationAttribute docAttribute : docList) { // see if the hash tables have been initialized Hashtable<?, ?> portHash = docAttribute.getPortHash(); if (portHash.isEmpty()) { docAttribute.createInstanceFromExisting(docAttribute); } docAttribute.removePort(name); docAttribute.removeProperty(name); } } /** Remove a file input/output. */ private void _removeInputOrOutput(String name, boolean isInput) throws Exception { Port port = getPort(name); if (port == null) { throw new IllegalActionException(this, "Could not find " + (isInput ? "intput" : "output") + " port " + name); } final IOType type = getPortIOType(port); port.setContainer(null); if (type == IOType.File) { removeParameter(name); } _removeInDocumentation(name); } /** Rename a port and parameter in the documentation. */ private void _renameInDocumentation(String oldName, String newName) throws Exception { List<KeplerDocumentationAttribute> docList = attributeList(KeplerDocumentationAttribute.class); for (KeplerDocumentationAttribute docAttribute : docList) { // see if the hash tables have been initialized Hashtable<?, ?> portHash = docAttribute.getPortHash(); if (portHash.isEmpty()) { docAttribute.createInstanceFromExisting(docAttribute); } String portDocStr = docAttribute.getPort(oldName); if (portDocStr != null) { docAttribute.removePort(oldName); docAttribute.addPort(newName, portDocStr); } String parameterDocStr = docAttribute.getProperty(oldName); if (parameterDocStr != null) { docAttribute.removeProperty(oldName); docAttribute.addProperty(newName, parameterDocStr); } } } /** Rename a parameter in each of the refinement command lines. */ private void _renameInCommandLines(String oldName, String newName) { for (Refinement refinement : entityList(Refinement.class)) { Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); // see if the command line exists in this refinement if (commandLineParameter != null) { // get the expression saved before the rename String expression = _refinementCommandLines.get(refinement); // do the rename in the expression String value = expression.replaceAll(Pattern.quote("$" + oldName), Matcher.quoteReplacement("$" + newName)); // rename the parameter name in references to the argument, e.g.,: // $(inputFile::argument) value = value.replaceAll(Pattern.quote("$(" + oldName + "::"), Matcher.quoteReplacement("$(" + newName + "::")); // set the new value in the parameter commandLineParameter.setExpression(value); //System.out.println("rename: new command line for " + refinement.getName() + ":" + //commandLineParameter.getExpression()); } } // update the default command line String value = _commandLineArguments.replaceAll(Pattern.quote("$" + oldName), Matcher.quoteReplacement("$" + newName)); value = value.replaceAll(Pattern.quote("$(" + oldName + "::"), Matcher.quoteReplacement("$(" + newName + "::")); _commandLineArguments = value; } /** Rename a component. * @param type the type of component to rename: property, port, or entity. * @param oldName the old name * @param newName the new name * @param newDisplayName the new display name. can be null */ private boolean _rename(String type, String oldName, String newName, String newDisplayName, NamedObj container) { // parameters: //<property name="Parameter"><rename name="name2"/></property> // ports: // <port name="a"><rename name="b"/></port> // refinements: // <entity name="Ramp"><rename name="r2"/></entity> StringBuilder moml = new StringBuilder("<"); moml.append(type); moml.append(" name=\""); moml.append(oldName); moml.append("\"><rename name=\""); moml.append(newName); moml.append("\"/>"); if (newDisplayName != null) { moml.append("<display name=\""); moml.append(newDisplayName); moml.append("\"/>"); } moml.append("</"); moml.append(type); moml.append(">"); MoMLChangeRequest request = new MoMLChangeRequest(this, container, moml.toString()); request.addChangeListener(this); _changeRequestError = false; requestChange(request); executeChangeRequests(); return !_changeRequestError; } /** Rename an input or output. * * @param oldName the old name * @param newName the new name * @param isInput if true, oldName refers to an input. * if false, oldName refers to an output. */ private void _renameInputOrOutput(String oldName, String newName, boolean isInput) { //System.out.println("rename input/output " + oldName + " to " + newName); boolean renamedParameter = renameParameter(oldName, newName); if (renamedParameter) { // set the display name if we're renaming an output String newDisplayName = null; if (!isInput) { newDisplayName = newName; } boolean renamedPort = _rename("port", oldName, newName, newDisplayName, this); // if we failed to rename the port, rename the parameter back // to the original name if (!renamedPort) { renameParameter(newName, oldName); } } } /** Restore the command line without changing them. */ private void _restoreCommandLines() { for (Refinement refinement : entityList(Refinement.class)) { Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); // see if the command line exists in this refinement if (commandLineParameter != null) { // get the expression saved before the rename String expression = _refinementCommandLines.get(refinement); commandLineParameter.setExpression(expression); } } } /** Save command line parameters in each refinement and clear them. This must be done * before a rename, since something is currently broken in MoMLParser for renames. */ private void _saveAndClearCommandLines() { _refinementCommandLines.clear(); for (Refinement refinement : entityList(Refinement.class)) { Parameter commandLineParameter = (Parameter) refinement.getAttribute(COMMAND_LINE_NAME); // see if the command line exists in this refinement if (commandLineParameter != null) { // save the expression String expression = commandLineParameter.getExpression(); _refinementCommandLines.put(refinement, expression); // clear the expression commandLineParameter.setExpression(" "); } } } /** Set the IOType parameter for a port. */ private static void _setPortIOTypeParameter(Port port, IOType type) throws IllegalActionException, NameDuplicationException { Parameter typeParameter = (Parameter) port.getAttribute(IO_TYPE_NAME); if (typeParameter == null) { typeParameter = new StringParameter(port, IO_TYPE_NAME); } typeParameter.setExpression(type.toString()); } /** Show or hide the mirrored ports connected to a port contained * by this actor based on the IOType. */ private void _showOrHideInsidePort(MultiCompositePort port) throws NameDuplicationException, IllegalActionException { // only show or hide output ports if (port.isOutput()) { // get the type IOType type = getPortIOType(port); // hide the inside port // NOTE: do not use insideSourcePortList() since it does not return transparent ports. //List<IOPort> insidePorts = port.insideSourcePortList(); List<IOPort> insidePorts = port.insidePortList(); //System.out.println("checking inside ports for " + port.getName() + ":"); for (IOPort insidePort : insidePorts) { //System.out.println(" " + insidePort.getFullName()); switch (type) { case File: new SingletonAttribute(insidePort, "_hideInside"); //System.out.println(" hiding inside file port " + port.getName()); break; case Data: Attribute attribute = insidePort.getAttribute("_hideInside"); if (attribute != null) { attribute.setContainer(null); } //System.out.println(" showing inside data port " + port.getName()); break; } } } } /** Make sure that each port in this actor has a corresponding port in * each refinement and that they are linked together. */ private void _updatePortsAndInsideLinks() throws IllegalActionException { for (Refinement refinement : entityList(Refinement.class)) { // add ports present in the container, but not in the refinement Set<Port> portsToMirror = new HashSet<Port>(); for (Object containerPortObject : portList()) { if (containerPortObject != control.getPort()) { final Port containerPort = (Port) containerPortObject; final String portName = containerPort.getName(); // see if the refinement has the port final Port refinementPort = refinement.getPort(portName); if (refinementPort == null) { //System.out.println("mirroring port found in container " + containerPort); portsToMirror.add(containerPort); } else { // see if the container and refinement ports are linked final String relationName = portName + "Relation"; Relation relation = getRelation(relationName); if (relation == null) { try { relation = newRelation(relationName); //System.out.println("creating relation " + relationName); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error linking port " + portName); } } if (!((ComponentPort) containerPort).isInsideLinked(relation)) { containerPort.link(relation); //System.out.println("linking " + relationName + " to " + containerPort); } if (!refinementPort.isLinked(relation)) { refinementPort.link(relation); //System.out.println("linking " + relationName + " to " + refinementPort); } } } } try { MultiCompositeActor.mirrorContainerPortsInRefinement(refinement, portsToMirror); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding ports to choice."); } // add ports present in the refinement, but not in the container, unless // they are the default input/output ports. portsToMirror.clear(); portsToMirror.addAll(refinement.portList()); for (Port port : portsToMirror) { final String portName = port.getName(); if (port != control.getPort() && getPort(portName) == null && !portName.equals(DEFAULT_INPUT_FILE_NAME) && !portName.equals(DEFAULT_INPUT_DIR_NAME) && !portName.equals(DEFAULT_OUTPUT_FILE_NAME) && !portName.equals(DEFAULT_OUTPUT_DIR_NAME)) { try { //System.out.println("mirroring port found in template " + port); IOPort containerPort = (IOPort) newPort(portName); if (((IOPort) port).isInput()) { containerPort.setInput(true); } else { containerPort.setOutput(true); } new SingletonAttribute(port, "_showName"); } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error adding ports to container."); } } } } // show or hide all the inside ports for (Object port : portList()) { try { if (port != control.getPort()) { _showOrHideInsidePort((MultiCompositePort) port); } } catch (NameDuplicationException e) { throw new IllegalActionException(this, e, "Error show/hiding inside port."); } } } /** If true, make sure last modification time for each output file * increases after executing the template. */ private boolean _checkOutputTimestampVal = true; /** Directory containing templates. */ private File _templateDir; private EditableChoiceStyle _choiceStyle; /** The default command line used for new refinements. */ private String _commandLineArguments = "$additionalOptions"; /** The template name used to create an empty refinement. */ private final static String EMPTY_TEMPLATE_NAME = "Blank"; /** The name of the attribute contained in input/output File ports. * The value of this attribute is the IOType. */ private final static String IO_TYPE_NAME = "_ioType"; /** A map to save all the refinement command lines before a rename occurs. */ private Map<Refinement, String> _refinementCommandLines = new HashMap<Refinement, String>(); /** If true, an error occurred during a change request originating in this actor. */ private boolean _changeRequestError = false; }