About Script Editor

Script Editor lets you create scripts, run them within-app to perform whatever tasks you want such as count blocks in a project, list up models by specific conditions…etc.

Script Editor in Astah System Safety
section divider

Create and edit scripts

You need to use version 8.0 or later to use Script Editor.
Go to [Tools] – [Script Editor] from main menu to open the Script Editor.

section divider

Choose a script language

You can use the ECMAScript or JEXL to write your scripts for Astah Script Editor.
You can switch it from the drop-down menu on the right corner of the Script Editor.

section divider

Run your scripts

  1. Write your scripts in the upper field.

2. Then go to [Action] – [Go] or click the [Run] button under the [Action] menu to run the script.

3. Then the result will appear in the lower field.

section divider

Sample Scripts

Here’re some practical sample scripts you can use!

SysML

Mind Map

MISC

STAMP/STPA

GSN

section divider

SysML

List up all the Blocks in the project file

var IBlock = Java.type("com.change_vision.jude.api.inf.model.IBlock");

blocks = astah.findElements(IBlock.class);
for (var b in blocks) {
    print(blocks[b].getName());
}

List up all the Packages and Blocks in the project file

//This script writes out the information of packages and Blocks.
//The current Astah project should have packages and Blocks.
run();
 
function run() {
    var project = astah.getProject();
    printPackageInfo(project);
}
 
function printPackageInfo(iPackage) {
    print("Package name: " + iPackage.getName());
    print("Package definition: " + iPackage.getDefinition());
 
    with(new JavaImporter(
            com.change_vision.jude.api.inf.model)) {
        // Display packages and classes
        var namedElements = iPackage.getOwnedElements();
        for (var i in namedElements) {
            var namedElement = namedElements[i];
            if (namedElement instanceof IPackage) {
                printPackageInfo(namedElement);
            } else if (namedElement instanceof IClass) {
                printClassInfo(namedElement);
            }
        }
    }
}
 
function printClassInfo(iClass) {
    print("Class name: " + iClass.getName());
    print("Class definition: " + iClass.getDefinition());
 
    // Display all attributes
    var iAttributes = iClass.getAttributes();
    for (var i in iAttributes) {
        printAttributeInfo(iAttributes[i]);
    }
 
    // Display all operations
    var iOperations = iClass.getOperations();
    for (var i in iOperations) {
        printOperationInfo(iOperations[i]);
    }
 
    // Display inner class information
    var classes = iClass.getNestedClasses();
    for (var i in classes) {
        printClassInfo(classes[i]);
    }
}
 
function printOperationInfo(iOperation) {
    print("Operation name: " + iOperation.getName());
    print("Operation returnType: " + iOperation.getReturnTypeExpression());
    print("Operation definition: " + iOperation.getDefinition());
}
 
function printAttributeInfo(iAttribute) {
    print("Attribute name: " + iAttribute.getName());
    print("Attribute type: " + iAttribute.getTypeExpression());
    print("Attribute definition: " + iAttribute.getDefinition());
}

List up Messages without operation in Sequence diagram

run();
 
function run() {
    var targets = searchMessagesWithoutOperation();
 
    if (targets.length === 0) {
        print('No target messages found');
        return;
    }
}
 
function searchMessagesWithoutOperation() {
    with (new JavaImporter(com.change_vision.jude.api.inf.model)) {
        var targets = [];
        var messages = astah.findElements(IMessage.class);
        for (var i in messages) {
            var message = messages[i];
            if (message.isReturnMessage() || message.isCreateMessage()) {
                continue;   // ignore
            }
            var operation = message.getOperation();
            if (operation === null) {
                targets.push(message);
                print('HIT: Message [' + message.getName()
                    + '] is Sequence diagram ['
                    + message.getPresentations()[0].getDiagram().getFullName('::')
                    + ']');
            }
        }
    }
    return targets;
}

Export Block information to CSV

//This script generates a CSV file about the blocks in the current model.
//CSV format:
// "Name of a Block", "Name of the parent model", "Definition of the class"
run();
 
function run() {
    exportClassesInCsv();
}
 
function exportClassesInCsv() {
    with(new JavaImporter(
            com.change_vision.jude.api.inf.model)) {
        classes = astah.findElements(IClass.class);
    }
     
    var csvFile = selectCsvFile();
    if (csvFile == null) {
        print('Canceled');
        return;
    }
    print('Selected file = ' + csvFile.getAbsolutePath());
    if (csvFile.exists()) {
        var msg = "Do you want to overwrite?";
        with(new JavaImporter(javax.swing)) {
            var ret = JOptionPane.showConfirmDialog(scriptWindow, msg);
            if (ret != JOptionPane.YES_OPTION) {
                print('Canceled');
                return;
            }
        }
    }
 
    with(new JavaImporter(
            java.io)) {
        var writer = new BufferedWriter(new FileWriter(csvFile));
         
        for(var i in classes) {
            var clazz = classes[i];
            var rowData = [];
            rowData.push(clazz.getName());
            rowData.push(clazz.getOwner().getName());
            rowData.push(clazz.getDefinition());
            writeRow(writer, rowData);
        }
         
        writer.close();
    }
}
 
function selectCsvFile() {
    with(new JavaImporter(
            java.io,
            javax.swing)) {
        var chooser = new JFileChooser();
        var selected = chooser.showSaveDialog(scriptWindow);
        if (selected == JFileChooser.APPROVE_OPTION) {
            var file = chooser.getSelectedFile();
            if (file.getName().toLowerCase().endsWith('.csv')) {
                return file;
            } else {
                return new File(file.getAbsolutePath() + '.csv');
            }
        } else {
            return null;
        }
    }
}
 
function writeRow(writer, rowData) {
    for (var i in rowData) {
        writeItem(writer, rowData[i]);
        if (i < rowData.length - 1) {
            writer.write(',');
        }
    }
    writer.newLine();
}
 
function writeItem(writer, data) {
    writer.write('"');
    writer.write(escapeDoubleQuotes(data));
    writer.write('"');
}
 
function escapeDoubleQuotes(data) {
    return data.replaceAll("\"", "\"\"");
}

Show TaggedValues

In order to use TaggedValues, you need to import Profiles.

function printTaggedValueInfo(model) {
    if (model == null) {
        return
    }
    var taggedValues = model.getTaggedValues();
    for each(var taggedValue in taggedValues) {
        print(taggedValue.getKey() + ":" + taggedValue.getValue())
    }
}

Show TaggedValues of models selected in the diagram

function printSelectedPresentationsTaggedValueInfo() {
    var viewManager = astah.getViewManager()
    var diagramViewManager = viewManager.getDiagramViewManager()
    var selectedPresentations = diagramViewManager.getSelectedPresentations()
    for each(var selectedPresentation in selectedPresentations) {
        printTaggedValueInfo(selectedPresentation.getModel())
    }
}

Show TaggedValue script is also required.

Show TaggedValues models selected in the tree

function printSelectedEntitiesTaggedValueInfo() {
    var viewManager = astah.getViewManager()
    var projectViewManager = viewManager.getProjectViewManager()
    var selectedEntities = projectViewManager.getSelectedEntities()
    for each(var selectedEntity in selectedEntities) {
        printTaggedValueInfo(selectedEntity)
    }
}

Show TaggedValue script is also required.

List up models with a specific stereotype

var IElement = Java.type('com.change_vision.jude.api.inf.model.IElement');
var Arrays = Java.type('java.util.Arrays');
 
// Search by stereotype
var stereotype = "stereotype";
 
for each(var element in astah.findElements(IElement.class)) {
    if (containsStereotype(element, stereotype)) {
        print(element.getName());
    }
}
 
function containsStereotype(element, stereotype) {
    var stereotypes = Arrays.asList(element.getStereotypes())
    return stereotypes.contains(stereotype)
}

Change object colors that have the same text in its definition

var infNamespace = 'com.change_vision.jude.api.inf'
var INamedElement = Java.type(infNamespace + '.model.INamedElement');
var TransactionManager = Java.type(infNamespace + '.editor.TransactionManager');
var Key = Java.type(infNamespace + '.presentation.PresentationPropertyConstants.Key');
  
// Color to change
var COLOR = "#BBCCFF";
// Common Keywords in definition
var IDENTICAL_STRING = "a";

run();
  
function run() {
    var currentDiagram = getCurrentDiagram();
    if (currentDiagram == null) {
        print("error: Please open a diagram first.");
        return;
    }
    var presentations = getPresentations(currentDiagram);
    var chengeColorPresentations = getIdenticalDefinitionPresentations(presentations, IDENTICAL_STRING);
    setColor(chengeColorPresentations, COLOR);
}
  
function getCurrentDiagram() {
    try{
        var viewManager = astah.getViewManager();
        var diagramViewManager = viewManager.getDiagramViewManager();
        return diagramViewManager.getCurrentDiagram();
    } catch(e) {
        return null;
    }
}
  
function getPresentations(currentDiagram) {
    try {
        return currentDiagram.getPresentations();
    } catch (e) {
        return new IPresentation[0];
    }
}
  
function getIdenticalDefinitionPresentations(presentations, identicalString) {
    var regularExpression = new RegExp("(.*)(" + identicalString + ")(.*)");
    var identicalDefinitionPresentations = [];
    for(var i in presentations) {
        var presentation = presentations[i];
        if (presentation == null) {
            continue;
        }
        var model = presentation.getModel();
        if (model == null) {
            continue;
        }
        if (!(model instanceof INamedElement)) {
            continue;
        }
        var definition = model.getDefinition();
        if (definition.match(regularExpression)) {
            identicalDefinitionPresentations.push(presentation);
        }
    }
    return identicalDefinitionPresentations;
}
  
function setColor(presentations, color) {
    try {
        TransactionManager.beginTransaction();
        for(var i in presentations) {
            var presentation = presentations[i];
            presentation.setProperty(Key.FILL_COLOR, color);
        }
        TransactionManager.endTransaction();
        print("Done for " + presentations.length + " objects");
    } catch (e) {
        TransactionManager.abortTransaction();
        print("error: Failed");
        print(e);
    }
}

Delete all Notes from currently-opened diagram

run();
 
function run() {
    var notes = getAllNotesInDiagramEditor();
    if (notes.length === 0) {
        return;
    }
 
    var TransactionManager = Java.type('com.change_vision.jude.api.inf.editor.TransactionManager');
    TransactionManager.beginTransaction();
    notes.forEach(function(note) {
        deleteElement(note);
    });
    TransactionManager.endTransaction();
}
 
function getAllNotesInDiagramEditor() {
    var diagramViewManager = astah.getViewManager().getDiagramViewManager()
    var diagram = diagramViewManager.getCurrentDiagram();
    if (diagram === null) {
        print('Open any diagram.');
        return [];
    }
 
    var presentations = Java.from(diagram.getPresentations());
    return presentations.filter(function(p) {
        return p.type.equals('Note');
    });
}
 
 
function deleteElement(presentation) {
    var modelEditor = astah.getModelEditorFactory().getBasicModelEditor();
    modelEditor.delete(presentation.getModel());
}

Add setter/getter operation to selected property

//This script generates the setter/getter operations for the selected attributes.
//You should select attributes in the StructureTree before running this.
run();
 
function run() {
    var attributes = getSelectedAttributesInProjectView();
 
    if (attributes.length === 0) {
        print('Please select attributes that you want to add setter/getter in StructureTree');
        return;
    }
 
    with(new JavaImporter(
            com.change_vision.jude.api.inf.editor)) {
        TransactionManager.beginTransaction();
        for (var i in attributes) {
            addSetterGetter(attributes[i]);
        }
        TransactionManager.endTransaction();
    }
}
 
function getSelectedAttributesInProjectView() {
    with(new JavaImporter(
            com.change_vision.jude.api.inf.model)) {
        var attributes = [];
        var projectViewManager = astah.getViewManager().getProjectViewManager();
        var selectedEntities = projectViewManager.getSelectedEntities();
        for (var i in selectedEntities) {
            var entity = selectedEntities[i];
            if (entity instanceof IAttribute) {
                attributes.push(entity);
                print('Target attribute: ' + entity.getName());
            }
        }
    }
 
    return attributes;
}
 
function addSetterGetter(attribute) {
    var editor = astah.getModelEditorFactory().getBasicModelEditor();
    var clazz = attribute.getOwner();
    var attributeName = attribute.getName();
    //setter
    var setter = editor.createOperation(clazz, getSetterName(attributeName), 'void');
    editor.createParameter(setter, attribute.getName(), attribute.getType());
    print('Added Setter Operation: ' + setter.getName());
    //getter
    var getter = editor.createOperation(clazz, getGetterName(attributeName), attribute.getType());
    print('Added Getter Operation: ' + getter.getName());
}
 
function getSetterName(attributeName) {
    return 'set' + attributeName;
}
 
function getGetterName(attributeName) {
    return 'get' + attributeName;
}
section divider

Mind Map

List up all the topics in currently-opened Mindmap

//This script writes out a list of text in the current mindmap.
//The format is like a WiKi.
var depth = 0;
var INDENT_STR = '  '; //2 spaces
var ITEM_MARKER_STR = '* ';
 
run();
 
function run() {
    with(new JavaImporter(
            com.change_vision.jude.api.inf.model)) {
        var diagramViewManager = astah.getViewManager().getDiagramViewManager();
        var diagram = diagramViewManager.getCurrentDiagram();
        if (!(diagram instanceof IMindMapDiagram)) {
            print('Open a mindmap and run again.');
            return;
        }
     
        var rootTopic = diagram.getRoot();
        depth = 0;
        printTopics(rootTopic);
    }
}
 
function printTopics(topic) {
    var topicLabel = topic.getLabel().replaceAll('\n', ' ');
    print(getIndent(depth) + ITEM_MARKER_STR + topicLabel);
 
    var topics = topic.getChildren();
    depth++;
    for (var i in topics) {
        if (topics[i].getType() == 'Topic') { //skip MMBoundary
            printTopics(topics[i]);
        }
    }
    depth--;
}
 
function getIndent(depth) {
    var indent = '';
    for (var i = 0; i < depth; i++) {
        indent += INDENT_STR;
    }
    return indent;
}

Open/Close subtopics by specifying the level of structure

var Key = Java.type('com.change_vision.jude.api.inf.presentation.PresentationPropertyConstants.Key');
var IMindMapDiagram = Java.type('com.change_vision.jude.api.inf.model.IMindMapDiagram');
var TransactionManager = Java.type('com.change_vision.jude.api.inf.editor.TransactionManager');
var level = 0;
var doOpen = undefined;
  
var TARGET_LEVEL = 1;//Specify the level here
  
run();
  
function run() {
    var diagramViewManager = astah.getViewManager().getDiagramViewManager();
    var diagram = diagramViewManager.getCurrentDiagram();
    if (!(diagram instanceof IMindMapDiagram)) {
        print('Open a mindmap and run again.');
        return;
    }
    var rootTopic = diagram.getRoot();
  
    try {
        TransactionManager.beginTransaction();
        reverseTopicVisibility(rootTopic);
        TransactionManager.endTransaction();
        print('LEVEL' + TARGET_LEVEL + 'Done');
    } catch (e) {
        TransactionManager.abortTransaction();
        print('error: LEVEL' + TARGET_LEVEL + 'Failed');
        print(e);
    }
}
  
function reverseTopicVisibility(topic) {
    if (isNaN(TARGET_LEVEL) || TARGET_LEVEL < 0) {
        throw { toString: function() { return 'TARGET_LEVEL needs to be Integer value'; } };
    }
    if (level === TARGET_LEVEL) {
        if (doOpen == undefined) {
        doOpen = topic.getProperty(Key.SUB_TOPIC_VISIBILITY) == 'false';
        }
        topic.setProperty(Key.SUB_TOPIC_VISIBILITY, doOpen);
    }
    var topics = topic.getChildren();
    level++;
    for (var i in topics) {
        if (topics[i].getType() =='Topic') { //skip MMBoundary
            reverseTopicVisibility(topics[i]);
        }
    }
    level--;
}
section divider

MISC

Print all the properties of the selected object

// This script prints the properties of the selected element.
// You should select an element in the DiagramEditor before running this.
run();
 
function run() {
    var targets = getSelectedPresentationsInDiagramEditor();
 
    if (targets.length === 0) {
        print('Please select an element in a diagram');
        return;
    }
 
    for (var i in targets) {
        printAllProperties(targets[i]);
    }
}
 
function getSelectedPresentationsInDiagramEditor() {
    var diagramViewManager = astah.getViewManager().getDiagramViewManager();
    return diagramViewManager.getSelectedPresentations();
}
 
function printAllProperties(presentation) {
    with(new JavaImporter(
            java.util)) {
        var props = presentation.getProperties();
        var keyList = new ArrayList(props.keySet());
        Collections.sort(keyList);
        print('---------------------------');
        for (var i = 0; i < keyList.size(); i++) {
            var key = keyList.get(i);
            var value = props.get(key);
            print(key + ': ' + value);
        }
        print('---------------------------');
    }
}

Display Astah edition you are currently running

//This script shows how to check the edition of Astah.
run();
 
function run() {
    if (!isSupportedAstah()) {
        print('This edition is not supported');
    }
 
    //Use a special API here.
    //Ex:
    //TransactionManager.beginTransaction();
    //Edit the astah model
    //TransactionManager.endTransaction();
}
 
function isSupportedAstah() {
    with(new JavaImporter(
        com.change_vision.jude.api.inf.editor)) {
        var edition = astah.getAstahEdition();
        print('Your edition is ' + edition);
        if (edition == 'SystemSafety') {
            return true;
        } else {
            return false;
        }
    }
}

Display Astah information you are currently running

print("AstahVersion : " + astah.getAstahVersion());
print("AstahEdition : " + astah.getAstahEdition());
print("AstahInstallPath : " + astah.getAstahInstallPath());
print("UserHome : " + Java.type('java.lang.System').getProperty('user.home'));
print("AstahModelVersion : " + astah.getAstahModelVersion());
print("AstahAPIVersion : " + astah.getAstahAPIVersion());
print("AstahAPIModelVersion : " + astah.getAstahAPIModelVersion());

Show customized dialogue using Java GUI

//This script shows a GUI by using AWT and Swing of Java.
 
with(new JavaImporter(
    java.awt,
    java.awt.event,
    javax.swing)) {
 
var frame = new JFrame("Frame title");
frame.setLayout(new FlowLayout());
 
var goButton = new JButton("Go!");
goButton.addActionListener(new ActionListener({
    actionPerformed: function(event) {
        JOptionPane.showMessageDialog(frame, "Hello!");
    }
}));
 
var closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener({
    actionPerformed: function(event) {
        frame.setVisible(false);
        frame.dispose();
    }
}));
 
frame.add(goButton);
frame.add(closeButton);
frame.setSize(150, 100);
//We must not use JFrame.EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//We can use 'astahWindow' instead of 'scriptWindow' here.
frame.setLocationRelativeTo(scriptWindow);
frame.setVisible(true);
}
section divider

STPA/STAMP

List up all the Control Actions in Control Structure Diagram

run()
 
function run() {
    with (new JavaImporter(com.change_vision.jude.api.stpa.model)) {
        facet = astah.getFacet(IStampFacet.FACET_SYMBOLIC_NAME)
        analysis = facet.getRootElement(IStpaAnalysis.class)
        components = analysis.getComponents()
        controlActions = getControlActions(analysis, components.get(0))
        controlActions.forEach(
            function(controlAction) {
                print('CA: ' + controlAction.getName())
            }
        )
    }
}
 
function getControlActions(analysis, component) {
    with (new JavaImporter(java.util, com.change_vision.jude.api.stpa.model)) {
        controlActions = new ArrayList()
        links = analysis.getLinks()
        links.forEach(
            function(link) {
                if (link instanceof IControlLink
                    && (link.getSource() == component || link.getTarget() == component)) {
                    controlActions.addAll(link.getActions())
                }
            }
        )
        return controlActions
    }
}

Check whether UCA has HCF

run()
 
function run() {
    with (new JavaImporter(com.change_vision.jude.api.stpa.model)) {
        facet = astah.getFacet(IStampFacet.FACET_SYMBOLIC_NAME)
        analysis = facet.getRootElement(IStpaAnalysis.class)
        ucas = analysis.getUnsafeControlActions()
        uca = ucas.get(0)
        hcfs = getHazardCausalFactors(analysis, uca)
        if (hcfs.isEmpty()) {
            print(uca.getIdentifier() + ' has no HCFs')
        } else {
            print(uca.getIdentifier() + ' has HCFs')
        }
    }
}
 
function getHazardCausalFactors(analysis, uca) {
    with (new JavaImporter(java.util)) {
        hcfs = new ArrayList()
        allHcfs = analysis.getHazardCausalFactors()
        allHcfs.forEach(
            function(hcf) {
                if (hcf.getUnsafeControlAction() == uca) {
                    hcfs.add(hcf)
                }
            }
        )
        return hcfs
    }
}

List up all the HCF from all the Loss Scenarios

run()

function run() {
  with (new JavaImporter(com.change_vision.jude.api.stpa.model)) {
    var facet = astah.getFacet(IStampFacet.FACET_SYMBOLIC_NAME);
    var analysis = facet.getRootElement(IStpaAnalysis.class);
    for (var i in analysis.diagrams) {
      var diagram = analysis.diagrams[i]
      if (diagram instanceof ILossScenarioTable) {
        print(diagram.name);
        var hazardCausalFactors = diagram.hazardCausalFactors;
        for (var j in hazardCausalFactors) {
          var hcf = hazardCausalFactors[j];
          print("  [" + hcf.identifier + "] " + hcf.description);
        }
      }
    }
  }
}

List up all the Scenarios from all the Loss Scenarios

run()

function run() {
  with (new JavaImporter(com.change_vision.jude.api.stpa.model)) {
    var facet = astah.getFacet(IStampFacet.FACET_SYMBOLIC_NAME);
    var analysis = facet.getRootElement(IStpaAnalysis.class);
    for (var i in analysis.diagrams) {
      var diagram = analysis.diagrams[i]
      if (diagram instanceof ILossScenarioTable) {
        var hazardCausalFactors = diagram.hazardCausalFactors;
        for (var j in hazardCausalFactors) {
          var hcf = hazardCausalFactors[j];
          for (var k in hcf.hazardScenarios) {
            var scenario = hcf.hazardScenarios[k];
            print(scenario.description);
          }
        }
      }
    }
  }
}
section divider

GSN

List up all InContextOf target goals

run()
 
function run() {
    with (new JavaImporter(com.change_vision.jude.api.gsn.model)) {
    goals = astah.findElements(IGoal.class)
        targets = getInContextOfTargets(goals[0])
        targets.forEach(
            function(target) {
                print('Target: ' + target.getIdentifier())
            }
        )
    }
}
 
function getInContextOfTargets(argumentAsset) {
    with (new JavaImporter(java.util, com.change_vision.jude.api.gsn.model)) {
        targets = new ArrayList()
        facet = astah.getFacet(IGsnFacet.FACET_SYMBOLIC_NAME)
        rootElement = facet.getRootElement(IModule.class)
        argumentationElements = rootElement.getArgumentationElements()
        argumentationElements.forEach(
            function(argumentationElement) {
                if (argumentationElement instanceof IInContextOf
                    && argumentationElement.getSource() == argumentAsset) {
                    targets.add(argumentationElement.getTarget())
                }
            }
        )
        return targets
    }
}

Check whether Goal has Solutions

run()
 
function run() {
    with (new JavaImporter(java.lang, java.util, com.change_vision.jude.api.gsn.model)) {
        goals = astah.findElements(IGoal.class)
        goal = goals[0]
        solutions = new HashSet()
        try {
            getSolutions(goal, solutions)
            if (solutions.isEmpty()) {
                print(goal.getIdentifier() + ' has no Solutions')
            } else {
                print(goal.getIdentifier() + ' has Solutions')
            }
        } catch (e) {
            if (e instanceof StackOverflowError) {
                print('Too many calls. SupportedBy may loop.')
            } else {
                throw e
            }
        }
    }
}
 
function getSolutions(goalOrStrategy, solutions) {
    with (new JavaImporter(com.change_vision.jude.api.gsn.model)) {
        facet = astah.getFacet(IGsnFacet.FACET_SYMBOLIC_NAME)
        rootElement = facet.getRootElement(IModule.class)
        argumentationElements = rootElement.getArgumentationElements()
        argumentationElements.forEach(
            function(argumentationElement) {
                if (argumentationElement instanceof ISupportedBy
                    && argumentationElement.getSource() == goalOrStrategy) {
                    target = argumentationElement.getTarget()
                    if (target instanceof ISolution) {
                        solutions.add(target)
                    } else if (target instanceof IGoal || target instanceof IStrategy) {
                        getSolutions(target, solutions)
                    }
                }
            }
        )
    }
}