BCMS.qea
Enterprise Architect project ver. 17.x
(Shape Script issue)
Currency.Java.qea
Enterprise Architect project ver. 17.x
(Re-engineering
& Code generation issues)
Hyperlink.qea
Enterprise Architect project ver. 17.x
Scripting.qea
Enterprise Architect project ver. 17.x
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.
Specialize
⇝Script Library -Tools-
⤳ list of (extant) adaptable scriptsDevelop
⇝Execution Analyzer -Source Code-
⇝Edit Analyzer Scripts -Scripts-
orExecute
⇝Analyzer -Tools-
⇝View Analyzer Scripts
Java setup within Windows 11
"C:\Program Files\Sparx Systems\EA\Java API\SSJavaCOM64.dll"
copied toC:\Windows\System32
"C:\Program Files\Sparx Systems\EA\Java API\eaapi.jar"
as Java libraryExample (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(); } }
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'
Key action(s)
Specialize
⇝JavaScript -Tools-
Example
Key action(s)
Specialize
⇝Script Library -Tools-
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();
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)
Add a Model using Model Builder…
(package within browser) ⇝Create from pattern
⇝Model Add-Ins
⇝Broadcast Types
- Perspective ⤳
Management
⇝Model Add-Ins
⤳ creation of a UML Class Diagram in which an “add-in” is modeledSpecialize -Add-Ins-
⇝Manage Addin
Develop
⇝Behavior -Source Code-
⇝Edit Behavior
Develop -Source Code-
⇝Behavior
⇝Edit Internal Code
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) ☛
- General-purpose
EA_Connect
- Etc.
- Model
EA_OnPreDeleteConnector
EA_OnPreDeleteElement
☛- Etc.
- Etc.
Model Add-In ⤳ Application Programming Interface -API-
App
☛ ⤳ Enterprise Architect running instanceDiagram
☛EventProperties
☛ObjectType
☛Repository
☛Session
☛- Etc.
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
- Based on
EA_OnPreDeleteElement
event ☛ avoid element suppression- Based on
EA_OnPostNewConnector
event ☛ force cardinality nearby black diamond (UML Composition) to be anything other than0..1
or1
(Model Validation events ☛ may play an equivalent role as well).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
Principle
Customization of element or connector (look&feel typically) resulting from applied stereotype
Stereotype introduction
Settings
⇝UML Types -Reference Data-
⤳Assign
Shape Script toFB
new stereotypeShape Script
Usage
Develop
⇝Files -Source Code-
⇝Import Source Directory …
Expected result
Exercise
- Add constant public
Dollar_change_rate
class attribute toBitcoin
classDevelop
⇝Synchronize -Source Code-
⇝Synchronize Package… -Synchronize with Code-
⤳Forward engineer (model -> source)
- Add
Dinar_algerien
as new currency in the UML Class DiagramDevelop
⇝Generate -Source Code-
⇝Generate Single Element -Generate Code-
Settings
⇝Options -Model-
⇝Source Code Engineering
⇝Default Language for Code Generation
Develop
⇝Options -Source Code-
⇝Edit Code Template -Templates-
Develop
⇝Options -Source Code-
⇝Reset Source Language… -Configure-
Develop
⇝Generate -Source Code-
⇝Generate All -Generate Code-
Develop
⇝Edit -Source Code-
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.
-right click-
(package within browser) ⇝Develop -Source Code-
⇝Options
⇝Set as Namespace Root
Settings
⇝Settings -Reference Data-
⇝Namespace Roots…
⇝Clear Namespace Attribute
(package)