Enterprise Architect Scripting & Automation Interface



Resources
Headlines
Scripting

Scripting is an internal Automation Interface based on, for instance, JavaScript, to deal with the Object Model Enterprise Architect also supports an external Automation Interface based on, for instance, Java.

Java Automation Interface

Java setup within Windows 11

  1. "C:\Program Files\Sparx Systems\EA\Java API\SSJavaCOM64.dll" copied to C:\Windows\System32
  2. "C:\Program Files\Sparx Systems\EA\Java API\eaapi.jar" as Java library

Example (Java Maven project )

public class Enterprise_Architect_Java_API {

    public static void main(String[] args) {
        // 'ea' directory as repository...
        // See POM for 'ea' repository setup
        // -right click- (project) >> Run Maven >> Goals...
        // deploy:deploy-file -DgroupId=org.sparx -DartifactId=ea -Dversion=1.0 -Durl=file:./ea/ -DrepositoryId=ea -DupdateReleaseInfo=true -Dfile=./lib/eaapi.jar
        System.out.println("Java working directory: " + System.getProperty("user.dir"));

        org.sparx.Repository model = new org.sparx.Repository();
        System.out.println("'model.GetIsSecurityEnabled()': " + model.GetIsSecurityEnabled()); // 'false'
        model.OpenFile("C:\\Users\\franc\\Desktop\\BCMS.qea");

        // Get the repository from execution *WITHIN* Enterprise Architect:
        // model = org.sparx.Services.GetRepository(processID); // 'processID' of Enterprise Architect execution instance is passed automatically...
        org.sparx.Collection<org.sparx.Package> packages = model.GetModels();
        for (short i = 0; i < packages.GetCount(); i++) {
            org.sparx.Package p = packages.GetAt(i);
            // model.WriteOutput("Script", p.GetName(), 0); // Write 'Script' tab of 'System Output' window...
            System.out.println(p.GetName() + " is a model as root package...");
        }
        // Database may be locked when security is enabled, so SQL 'UPDATE' may fail:
        model.Execute("UPDATE t_object SET Status = 'Approved' WHERE Object_Type = 'Package';");
        model.Execute("UPDATE t_object SET GenType = NULL;"); 
        model.Execute("COMMIT;");
        model.CloseFile();
        model.Exit();
    }
}
Python Automation Interface

Example (Python file )

# EA.py

print("Enterprise Architect with PYTHON...")

from singleton_decorator import singleton # https://pypi.org/project/singleton-decorator/ -> 'pip install singleton-decorator'
import time
import win32com.client # 'pip install pywin32'

@singleton
class Enterprise_Architect:
    def __init__(self):
        try:
            self._EA = win32com.client.DispatchEx("EA.App") # Kill EA instance in Windows 'Task Manager'
            print("Enterprise Architect instance created...")
            self._Repository = self._EA.Repository # models = self._Repository.models
            self._Repository.OpenFile("C:\\Users\\franc\\Desktop\\Age_classification.qea")
            print("'self._Repository.RepositoryType()': ",self._Repository.RepositoryType())
            print("Name of diagram: ",self._Repository.GetDiagramByGuid("{53E40320-B104-4c1f-9243-70E3E1D471B1}").Name) # GUID of 'Age_classification' diagram: {53E40320-B104-4c1f-9243-70E3E1D471B1}
            time.sleep(1)
            self._Repository.CloseFile()
            self._Repository.Exit()
            print("Enterprise Architect instance stopped... No effect? -> kill EA instance in Windows 'Task Manager'")
        except Exception as e:
            print(e)

    @classmethod
    def Get_instance(file_URL):
        repository = win32com.client.GetActiveObject("EA.App").Repository # EA instance is already running...
        repository.CreateObject("EA.Repository")
        repository.OpenFile(file_URL)
        time.sleep(1)
        repository.CloseFile()
        repository.Exit()
        return None

ea = Enterprise_Architect() # creates instance
ea_ = Enterprise_Architect() # returns same instance because of '@singleton'
print(ea == ea_) # 'True'
JavaScript console

Key action(s)

Example

JavaScript batch program

Key action(s)

Example

!INC Local Scripts.EAConstants-JavaScript
/* Ajout automatique d'hyperliens sur des objets (étude de cas CIMPA SAS) */
 
function Hyperlink() {
	Repository.EnsureOutputVisible("Script"); // Open 'System Output > Script' window for message display...
	
	var hyperlinks = new Map();
	hyperlinks.set("Franck Barbier","https://FranckBarbier.com");
	hyperlinks.set("B--Di","https://BarbierDarnal.com");
	
	// Create a new model root named "Modified model":
	var root as EA.Package;
	root = Repository.Models.AddNew("Modified model","");
	root.Update();
	// Create "Modified hyperlink" child package of "Modified model":
	var target_package as EA.Package;
	target_package = root.Packages.AddNew("Modified hyperlink","Class"); // "Class" -> 'Set View Icon...'
	target_package.Update();
	
	var target_diagram as EA.Diagram;
	target_diagram = target_package.Diagrams.AddNew("Modified hyperlink","Class");
	target_diagram.Notes = "Ajout automatique d'hyperliens sur des objets (étude de cas CIMPA SAS)";
	target_diagram.Update();
	
	var source_package = Repository.Models.GetByName("Model").Packages.GetByName("Hyperlink");
	// Session.Output("'source_package' count: " + source_package.Elements.Count); // ''source_package' count: 4'
	
	hyperlinks.forEach(function(value,key) {
		var element = source_package.Elements.GetByName(key);
		if(element) {
			var element_copy = target_package.Elements.AddNew(element.Name,element.Type); // Copy of original object...
			// "Text" instead of "Hyperlink" plus customization:
			var hyperlink = element_copy.Elements.AddNew(value, "Hyperlink");
			// element_.Update(); // Update in browser...
			var element_in_diagram as EA.DiagramObject;
			element_in_diagram = target_diagram.DiagramObjects.AddNew("",""); // No style at all...
			element_in_diagram.ElementID = element_copy.ElementID; // Refer to existing object in browser...
			element_in_diagram.Update();
			
			element_in_diagram = target_diagram.DiagramObjects.AddNew("",""); // No style at all...
			element_in_diagram.ElementID = hyperlink.ElementID; // Refer to existing hyperlink in browser...
			element_in_diagram.Update();			
		}
	});
	// Apply layout: https://sparxsystems.com/forums/smf/index.php?topic=5883.0
}
// Test:
Hyperlink();
Model Add-In and t☛

Principle

Enterprise Architect supports predefined events from which a script as “add-in” acts as a subscriber. The list of events is offered as a package named Broadcast Types.

Key action(s)

Broadcast Types

Model Add-In ⤳ creation

Model Add-In ⤳ management

Status is user-oriented, i.e., Optional means that users may decide Model Add-In usage or not.

Model Add-InEnterprise Architect predefined events (i.e., signals)

Model Add-InApplication Programming Interface -API-

Model Add-InEnterprise Architect connection handler

Model Add-InEnterprise Architect connection event

Model Add-In ⤳ execution

Reload is the way to execute provided that Load on Startup has been checked.

Exercise

Session.Output("EA_OnPostNewConnector...");
// 'return' must be 'true' to get cardinality as '1' or '0..1':
return this.EA_OnPostNewConnector_handler(Repository,Info);
Session.Output("EA_OnPostNewConnector_handler...");
// Session.Output(Info.ObjectType); '46' -> Connector
var connector_id = Info.Get(Info.Count - 1); // Only one...
// Session.Output(connector_id);
var connector = Repository.GetConnectorByID(connector_id);
if(connector.Type === "Aggregation" && connector.Subtype === "Strong") 
	Session.Output("UML BLACK DIAMOND");
if(connector.ClientEnd.Aggregation === 2) { // Composite
	connector.ClientEnd.Cardinality = "1";
	connector.ClientEnd.Role = "-1- or -0..1- only!";
	if(connector.ClientEnd.Update() === false)
		Session.Output(connector.ClientEnd.GetLastError(),1);
}
else
	if(connector.SupplierEnd.Aggregation === 2) { // Composite
		connector.SupplierEnd.Cardinality = "1";
		connector.SupplierEnd.Role = "-1- or -0..1- only!";
		if(connector.SupplierEnd.Update() === false)
			Session.Output(connector.ClientEnd.GetLastError(),1);
	}
// connector.Update(); // Useless...
return true;

Principle

Search results in XML format after (probable) pre-processing…

Add-In Search signature

Add-In Search code

Add-In Search execution

Shape Script

Principle

Customization of element or connector (look&feel typically) resulting from applied stereotype

Stereotype introduction

Settings UML Types -Reference Data-Assign Shape Script to FB new stereotype

Shape Script

Usage

Re-engineering

Expected result

Exercise

  1. Add constant public Dollar_change_rate class attribute to Bitcoin class
  2. Develop Synchronize -Source Code- Synchronize Package… -Synchronize with Code-Forward engineer (model -> source)
  3. Add Dinar_algerien as new currency in the UML Class Diagram
  4. Develop Generate -Source Code- Generate Single Element -Generate Code-
Code generation

Expected result

from abc import ABC, abstractmethod 

class Currency(ABC):
    def __init__(self,common_symbol,iso_code,iso_symbol):
        self._common_symbol = common_symbol
        # Etc.
    def rate(currency):
        pass
    @abstractmethod
    def to_dollar_rate():
        pass
    def convert_to_dollar(amount):
        pass
    @abstractmethod
    def to_euro_rate():
        pass
    def convert_to_euro(amount):
        pass

Euro = Currency("€", 978, "EUR") # 'TypeError: Can't instantiate abstract class Currency with abstract methods to_dollar_rate, to_euro_rate'
print('Euro: ', Euro._common_symbol)

Namespaces

Namespaces mainly act as location paths used by code generation especially.