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

var zero = Repository.Models.GetByName("Model").ParentID;
Session.Prompt(zero,1);
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 ☛

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-In ⤳ Enterprise Architect predefined events (i.e., signals) ☛

Model Add-In ⤳ Application Programming Interface -API-

Model Add-In ⤳ Enterprise Architect connection handler

Model Add-In ⤳ Enterprise Architect connection event

Model Add-In ⤳ execution

Check Load on Startup for immediate execution

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 engineering (model -> source)
  3. Add Dinar_algerien as new currency within UML Class Diagram (check that Filename Enterprise Architect “Project” property is set up!)
  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