Recent posts

#31
Hello Archi Community!  :)

I am currently facing a challenge while using the Archi software and I'm hoping to find some assistance here.

My goal is to create specializations of elements that could be used between different views while preserving some characteristics such as name-value properties and graphical aspects.

With "Specializations Manager" alone it is not possibie to satisfy this need. So I attempted to realize a "template view" and created the elements of interest there, with the intention of copying and pasting them into other views. However, I noticed that the first paste operation results in copying an instance of the same object, which also modifies the properties of the "template elements" in the corresponding view. To obtain a copy of the same object, I need to perform the paste operation twice.

Similarly, when I use the "Duplicate" option for a view, the instances of the same elements are retained, leading to changes in the properties of the elements in both views.

For this reason, I would like to ask you if there is a way to:
  • Generate a "template" of a desired element starting from a specialization, while preserving the graphic and key-value properties of the object.
  • Copy and paste the desired element into another view without needing to perform the operation twice to obtain a copy.
  • Duplicate a view, creating copies of the objects rather than retaining the same instances.

I am using Archi 5.3 with ArchiMate 3.2.

Thank you in advance for your time and consideration.
#32
I love Archi! Incredible tool! This is why I invested quite a portion of my free time to develop archi-powertools. The tools pay off! Today, as business-as-usual, archi-powertools-verifier notified me that a new connection to yet another Kafka had just been added by the developers to that setup I'm describing in the topic. It took me five minutes to think carefully which of the views on the model best represent the new stuff, do all beauty work, write commit message, and click "OK". (The HTML report gets generated and published automatically.) Including two minutes wasted as I initially made the Flow relation go wrong direction (oops!). The verifier spotted the problem. +1 element and +1 relation in the model, 100% guarantee that the model is in perfect shape.
#33
jArchi / Re: error adding existing elem...
Last post by Mate - May 21, 2024, 19:46:24 PM
Thank you, Phil. I now know my mistake and the distinction between diagram objects and model concepts. Thank you for the explanation.

Also grateful for the tips on JS programming. I only occasionally dabble in programming, and this is my first foray into JS and jArchi. So am most thankful for all the guidance that can help me improve :).
#34
General Archi Discussion / Re: How I cope with model of 4...
Last post by Phil Beauvoir - May 21, 2024, 18:48:35 PM
Hi,

thanks for sharing this with the Archi and ArchiMate community! I'm sure everyone will find this very useful. :-)

Phil
#35
Bonus #1: Model linting
I can use the same technique and same instruments to validate internal properties of architecture models against a set of rules expressed in SQL and CQL queries. For example, my automation checks that if a NiFi processor group is presented on a ArchiMate view, the view also contains all model elements which are data source or data sink for this processor group. Otherwise, the view would mislead me and others about ins and outs of this processor group. Check out this example of SQL queries which implement such sort of verifications.
#36
jArchi / Re: error adding existing elem...
Last post by Phil Beauvoir - May 21, 2024, 11:09:46 AM
Hi,

The error means that there is no method with the signature:

View.add(diagramObject, x, y, w, h);

Your script is getting objects based on the current selection here:

return $(selection).find("element").filter(e => {

But if the current selection is a View then the elements returned are actually diagram objects, not model concepts. In that case you need to reference the underlying concept like this:

View.add(e.concept, 100, 100, 140, 60);

BTW if you want to select all elements in the model rather than the current selection you can just do this:

return $("element").filter(e => {

Some possible tips:

1. You probably know this but I'll mention it anyway. You don't actually need a "main()" function, you can just put that code block at the start of the script.
2. Because you are catching exceptions in a try/catch block you don't get to see the line number in the script where the error occurred in the console output. I had to remove the try/catch to see the line number where the problem occurred.

Hope that helps!
#37
jArchi / Re: error adding existing elem...
Last post by Mate - May 21, 2024, 00:00:52 AM
seems to work as expected if the selection is the model or a folder. If the selection is a view then I get this error. Do I need to do some additional transformation for elements selected from a view vs elements selected from the whole model or a folder in the model?
#38
jArchi / error adding existing elements...
Last post by Mate - May 20, 2024, 22:27:10 PM
I have written a script ( this is my third jArchi script, so still learning  :) ) that selects elements in a model based on a combination of properties and adds these to a new view. All seems to be as expected except for adding the element to the view. Below is the script followed by the error that I am getting. I expect I am not doing something right. Any guidance is much appreciated.

console.show();
console.clear();
console.log("Start \r");

debug = true;

var propertyDict = {
    "source": "Legacy",
    "state": "Enabled",
    "taxonomyL0": "Common"   
};

function findMatchingElements(properties, matchAll) {
    try {
        return $(selection).find("element").filter(e => {
            debug ? console.log("Checking element: " + e.name + "\r") : true;
            var matches = matchAll ? true : false;
            for (var key in properties) {
                var elementProp = e.prop(key) ? e.prop(key).trim().toLowerCase() : "";
                var filterProp = properties[key] ? properties[key].trim().toLowerCase() : "";
                debug ? console.log("Property: " + key + ", Element: " + elementProp + ", Filter: " + filterProp + "\r") : true;

                if (matchAll) {
                    if (elementProp !== filterProp) {
                        matches = false;
                        break;
                    }
                } else {
                    if (elementProp === filterProp) {
                        matches = true;
                        break;
                    }
                }
            }
            return matches;
        });
    } catch (error) {
        console.error("Error finding matching elements: " + error);
        return [];
    }
}

function addElementsToView(elements, viewName) {
    try {
        var View = $("view").filter(v => v.name === viewName).first();
        if (!View) {
            debug ? console.log("Creating a new view called: " + viewName + "\r") : true;
            View = model.createArchimateView(viewName);     
        } else {
            debug ? console.log("Selecting the existing view: " + viewName + "\r") : true;
        }

        elements.each(e => {
            debug ? console.log("Adding element: " + e.name + " to the view: " + viewName + "\r") : true;
            View.add(e, 100, 100, 140, 60); // x, y, width, height
        });

        // view.openInUI();
        debug ? console.log("Elements added to view: " + viewName) : true;
    } catch (error) {
        console.error("Error adding elements to view: " + error);
    }
}

function main() {
    try {
        if (!model) {
            throw new Error("No model selected. Please select a model before running the script.");
        }
        var matchAllProperties = true; // Set to false to match any property
        var matchingElements = findMatchingElements(propertyDict, matchAllProperties);
        debug ? console.log("Matching elements: " + matchingElements.length + "\r") : true;
        addElementsToView(matchingElements, propertyDict.source);
    } catch (error) {
        console.error("Error in main function: " + error);
    }
}

main();
console.log("done \r");

QuoteError adding elements to view: TypeError: invokeMember (add) on com.archimatetool.script.dom.model.ArchimateDiagramModelProxy failed due to: no applicable overload found (overloads: [Method[public com.archimatetool.script.dom.model.DiagramModelConnectionProxy com.archimatetool.script.dom.model.ArchimateDiagramModelProxy.add(com.archimatetool.script.dom.model.ArchimateRelationshipProxy,com.archimatetool.script.dom.model.DiagramModelComponentProxy,com.archimatetool.script.dom.model.DiagramModelComponentProxy)], Method[public com.archimatetool.script.dom.model.DiagramModelObjectProxy com.archimatetool.script.dom.model.ArchimateDiagramModelProxy.add(com.archimatetool.script.dom.model.ArchimateElementProxy,int,int,int,int,boolean)], Method[public com.archimatetool.script.dom.model.DiagramModelObjectProxy com.archimatetool.script.dom.model.ArchimateDiagramModelProxy.add(com.archimatetool.script.dom.model.ArchimateElementProxy,int,int,int,int)]], arguments: [JavaObject[application-service: AzureSQLAnalytics(DefaultWorkspace-ef74c932-a6bc-4e9e-aca8-d91d2710dce1-NCUS) (com.archimatetool.script.dom.model.DiagramModelObjectProxy)] (HostObject), 100 (Integer), 100 (Integer), 140 (Integer), 60 (Integer)])
#39
Hi all!

I want to share my story about how I deal with a model representing a real complex data processing setup that constantly mutates. I have been on a challenge of building the model and automation around in course of past two months as a part-time assignment. Now I'm  having solid proofs that my setup flies flawlessly and is saving me and the team a ton of time and effort each day. I'm very much proud of it!

My situation is that there is a team of approximately ten data engineers and devops who are full-time busy on improving or modifying the setup. A whole bunch of Apache NiFi dataflows running on several AWS EC2 instances comprise the setup. They pull data from several dozens of external APIs, then fan out processed data to downstream consumers, as well as data storage services. The whole setup is undergoing migrating from one AWS region to another. Those APIs live their own life, sometimes changing their endpoint location, or getting decommissioned. Or a new API appears.

How do I make sure that my architecture diagrams always correctly represent all that pretty complex "reality"? And how do I sleep well spending just 10 minutes a day fixing drift, when it gets detected?

The keyword here is "drift detection". Let me describe my toolchain.

Data harvesting. I use two sources to fetch all necessary data about "the real world": AWS CLI output and NiFi flow definition JSON files.

Data preparation. Before feeding the data to model validation scripts, I prefer to transform it to comma- or tab-separated text files. Making AWS CLI to produce such output is not a problem at all. Retrieving necessary data from NiFi flow definitions is the trickiest part of the challenge. Those JSON files that the data harvesting script retrieves from the servers, are around two million lines in total, if pretty-printed. I chose jq to do all the heavy-lifting, looping through objects, looking up for NiFi processor group and processor descriptions, and matching parameter substitutions in expressions against values in context definitions. What jq passes output are two comma-separated files. One maps NiFi root process group names to ids of AWS EC2 instances the groups run on. The second file lists all data sources and data sinks the process groups have in configuration of their data processors. What I'm interested in first of all is to know what kind of database, data streaming service or API is the NiFi processor's peer, and what is its URL, address or identification. I want to know all the ins and outs of data processing setup under analysis.

Validating model correctness. For marching my ArchiMate model against "the real world" data, I employ archi-powertools-verifier. The tool leverages Docker Compose to orchestrate Archi, Neo4j and sqllite containers.
The basic idea is pretty straightforward. A model validation batch does the following.
  • Convert content of ArchiMate model to set of comma-separated files;
  • Run SQL database engine (sqlite) or graph database engine (Neo4j);
  • Make it import model files and any additional data we have as result of data preparation we did before;
  • Run the set of SQL or CQL (Neo4j) queries I wrote. The queries compare what is in the tables (or elements and relationships, if Neo4j) which contain the model against what is those which contain the "real world" data. Read this for mode details and examples.

So, once a day my automation runs data harvesting, data preparation and model validation scripts. If my SQL and CQL scripts detect any discrepancies between the architecture model and AWS infrastructure or NiFi flow definitions, I get Drift detected! lines in the output accompanied with necessary problem descriptions and resource names or ids. To bring the architecture model back to state when it correctly represents the NiFi flows, I edit the model manually in Archi. Before committing my changes to git, I validate the model one more time. When there are no more drift warnings in the output, I'm ready to push the updated model to the repository to make it available to other collaborators. Doing this process again and again routinely, I have already collected statistics that our NiFi setup gets 2 to 4 changes requiring mirroring in the model each week. When drift is detected, it normally takes 10 or 15 minutes to edit, re-validate, commit and push changes. And I'd say that those several minutes spent is nothing if we consider that that is all the cost of making it guaranteed that the system architecture model is fully correct 100% of time.
#40
jArchi / Re: Hide all relationship line...
Last post by Mate - May 17, 2024, 20:10:51 PM
That works perfectly. Thank you. :)