Tracking Dependencies with Components and XMI

Tracking Dependencies with Components and XMI

his fourth installment in an ongoing series on XMI leads me to a discussion of components. Components are an essential building block of your data model and are thus a valuable asset to any developer who is using models and XMI. In this article, I will discuss how components are linked together and how they interact with nodes, UML’s method of representing hardware. This article should give the final pieces to building a system that can track software dependencies on an enterprise scale. The idea is very similar to what many banks are building to track their software assets.

So just what, exactly, is a component? I discussed that very issue in the opening paragraph of an earlier article on component diagrams, but here I am really just concerned with what it means from a data perspective. The data that we are concerned about answers the questions: How many components do I have that have the same attributes? Which component depends upon other components?

Components come in two different varieties: one is the abstract representation of a component and the other represents the implemented software. There are numerous applications for mining components using XMI and C#. For example, I can study how one component relies on another and use the information to map my software dependencies. Inventory management is another use that I discussed in an earlier article on nodes. In short, the more you know about your components, the better you will understand your enterprise as a whole.

Reading a Component from an XMI File

Figure 1. Abstract Component: The Payments component is still in development. It is being developed in C#.NET version 2.0. In this example I used the stereotype <> to indicate that the software is in development. Another way to indicate software in development is to add a “status” tag that is set to development.

The first example that I have developed shows an abstract component (see Figure 1). Abstract components develop the reference architecture for an application; they are always components that are deployed but they are either in development or will exist generically in a couple of different deployments. In contrast, instantiated components represent the actual implementation of a particular component.

An abstract component, for example, is the Payments component. It is stereotyped as software in development with version information pertaining to the .NET framework and the C# language. The Payments instantiated component is an executable component, which is stereotyped as an executable with its applicable version information referring to the version of Payments, not to the .NET framework version as in the abstract component.

Author’s Note: The code in this article builds on the sample code developed throughout this XMI series.

Now let’s take a look at the code for this example. The first thing to note is that UML tags, such as the Language and Version tags used in the Payments component, are not encapsulated in the XML tag for a component. They are listed in the XML as if they were separate parts like a component or node. The only way to differentiate between a component’s tag and a node’s tag is by checking the ModelElement id. To solve this I added another hash table for components. My code checks which table has the key that will let me switch between node tags and component tags.

Figure 2. Output: The screen shot shows the results of finding the Payments component using XMI.
if (_nodes.ContainsKey(attrRef)) {    Node attrNode;    attrNode = (Node)_nodes[attrRef];    _nodes.Remove(attrRef);    switch (attrName)       {       case "CPU":              ...       }       _nodes.Add(attrRef, attrNode);   }       else {       if (_components.ContainsKey(attrRef))       {       Component attrComponent;       attrComponent = (Component)_components[attrRef];       _components.Remove(attrRef);    switch (attrName)    {       case "Language":              ...    }       _components.Add(attrRef, attrComponent);  }}

The end result of the first example is that I can read the component from the XML file, find its name and the tags for the programming language it is written in, and find the version of the .NET framework that the language is hosted in (see Figure 2).

Differentiating Components and Component Instances
In the next example I will add a component instance with the same name as the component from the previous example. This provides for some interesting XMI. The only difference in XMI between an instantiated component and an abstract component is one encapsulated XMI statement:

For those that use Sparx Systems’ Enterprise Architect the classifier statement makes this unique. However, if exported to another tool (without the EA extensions), there is no way to tell the difference between the component and component instance.

Figure 3. Adding Traceability: The Payments executable has the Payments development software as its classifier. This adds traceability with the reference architecture for the Payments executable.

To separate the two components I will have to check for the tag. Because the tag is encapsulated in the Component XMI this is easy enough. There is one other small problem: There is a version tag in both components, but they mean two different things. In the instantiated component the version tag refers to the component, and in the abstract component it refers to the language version. So to separate the components I have to identify them as being either abstract or instantiated. In code I’ve added a few fields to the component object to differentiate between the component and component instance:

public string Classifier{       get       {       if (!_Instance)              {                     return " ";              }                     return _Classifier;              }       set       {       if (!_Instance)              {                     _Classifier = " ";              }else {                     _Classifier = value;              }       }}

I need to check whether the component is an instance before assigning a value to the classifier. This seems obvious but the tendancy is to assume that the code using the Component class checks for the _Instance flag before getting _Classifier.

Figure 4. Comparing Tags: The output demonstrates that the only difference between the two components is the classifier tag and the component ID. Without this tag they would be indistinguishable. Notice that the classifier tag in the second component refers to the original component ID. Also the component and component instance have the same name but different XMI IDs.

In the addComponent method I check the XMI to see if a component is an instance and then assign it as a clasifier if it is.

private void AddComponent(XmlTextReader p_readXMI){string componentID;string componentName;string stereotypeName;Component component;componentName = p_readXMI.GetAttribute("name");componentID = p_readXMI.GetAttribute("");component = new Component(componentID);component.Name = componentName;while (p_readXMI.Read() &&      (p_readXMI.NodeType == XmlNodeType.Element ||        p_readXMI.NodeType == XmlNodeType.Whitespace))   {     switch (p_readXMI.LocalName)       {       case "ModelElement.stereotype":       while (p_readXMI.Read() &&             (p_readXMI.NodeType == XmlNodeType.Element ||             p_readXMI.NodeType == XmlNodeType.Whitespace))       {              if (p_readXMI.LocalName == "Stereotype")              {              stereotypeName = p_readXMI.GetAttribute("name");              component.Stereotype = stereotypeName;              }       }       break;       case "ModelElement.taggedValue":       while (p_readXMI.Read() &&     (p_readXMI.NodeType == XmlNodeType.Element ||      p_readXMI.NodeType == XmlNodeType.Whitespace))       {       if ((p_readXMI.LocalName == "TaggedValue")&&          (p_readXMI.GetAttribute("tag") == "classifier"))          {              component.Instance = true;              component.Classifier = p_readXMI.GetAttribute("value");          }       }       break;    }  }_components.Add(componentID, component);}

The final output (see Figure 4) has one abstract component without a classifier ID and one instantiated component with the classifier for the abstract component to which it refers.

Relating Component Instances and Node Instances
The third example adds a node instance to the diagram. (I had to add the <> stereotype to the dependency because SparxSystems Enterprise Architect thought it was bad UML to leave it off! See Figure 5.) I also added a dependency from the component instance to the node instance. In UML diagrams this has the stereotype of <> indicating that the component is deployed on the hardware that the node represents.

Figure 5. Adding a Node Instance: The Payments executable component instance is deployed on the Car Server. Notice that the arrow for the <> dependency points to the server where the software is deployed. In deployments the component and the nodes are instances not abstractions.
Figure 6. Client and Supplier: The dependency has two pieces, a client and a supplier. In this case the client is Payments. The supplier, Car, is the server. When this example is output as a diagram the first end of the dependency is the CAR instance (supplier), while the second is the payments (client).

Adding a dependency is the same as adding an association except that each end of an association points to the same thing. In dependencies one end is the supplier and the other is the client:

The supplier points to what the component is dependent upon. In this case, it is the CAR Node. The client, on the other hand, is the dependee or in this case the payments component (see Figure 6).

Putting It All Together
The final example combines managing the dependencies between two nodes with managing the dependencies between a component and a node to track the dependency between a component instance on one piece of hardware [node] with a component instance on another. This example shows how the Finance component instance is dependent on the Payments instance through the dependencies they have on the their nodes (see Figure 7). Just to show that the example is somewhat generic, I also show how the Payments instance is dependent on the Finance instance.

Figure 7. Dependency: This diagram depicts the dependency of the Finance component on the Payments component.
Figure 8. Output No. 1: The output from the XMI in Figure 7 has the component instance of Finance depending upon Payments.

The output (Figure 8) corresponds with the example diagram, where the Finance component instance is dependent on the Payments component. The second output (see Figure 9) shows that it can be the other way around. The Payments component is dependent on the Finance component. In a real situation you would of course use the directional indicator on the node’s associations to constrain it to a one-way dependency.

Figure 9. Output No. 2: The second output from Figure 7 demonstrates that it can work both ways?Payments depends upon Finance.

My first cut at coding a solution was to do the step-by-step approach (see Listing 1). Even though the code works, it is not very coherent. Even with some added comments, it is difficult to tell what each part of the code is doing.

If I use the pipes and filters pattern the code is easier to understand and change. There is little need for documentation (which we know all programmers dislike).

public static void Main(string[] args){string name = ReadString("Please enter the XMI filename : ");string dependencyQuery =         ReadString("Please enter the component instance : ");XMIFactory XFact = new XMIFactory(name);String componentName = XMIFunctoids.findComponentName(                   XMIFunctoids.findNodeComponentDependency(                   XMIFunctoids.findNodeNodeAssociation(                     XMIFunctoids.findComponentNodeDependency(                     XMIFunctoids.findComponent(dependencyQuery)))));                     System.Console.WriteLine(               "Connection from one dependency to another is : "                + dependencyQuery + " : " + componentName);System.Console.ReadLine();}

This discussion of nodes and components should get you started developing asset management system to mine your diagrams. There are many more uses for XMI including creating diagrams from the company’s assets (in a database or flat file), validating class diagrams, and building a UML editor.

See also  FACE Report: Fintech Loan Disbursements Surge 49% in FY24

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist