Skip to main content

IBM DOORS Links

·9 mins

Linking and traceability in IBM DOORS allow users to build and track relationships between requirements across a project’s lifecycle.

By following these links, you can monitor how changes to one requirement affect others, ensuring project integrity.


1. Key Concepts and Terminology #

To master linking in DOORS, you must understand the distinct roles of the following components:

doors-concepts

ConceptDescription
LinkA relationship between a source object and a target object
Outlink (Outgoing Link)A link viewed from the perspective of the source object, pointing away to a destination
Inlink (Incoming Link)A link viewed from the perspective of the target object, arriving from a source
Link ModuleA specialized module that does not store actual links, but rather the Linksets that define the rules for those links
LinksetA data structure within a Link Module that defines a relationship between a specific pair of modules (source and target)
Link Module DescriptorA pairing definition set at the folder or project level. It specifies which Link Module should be used for links between specific modules and whether that module is mandatory or overridable
LinkRefA DXL data type representing a reference to a link. It is commonly used when iterating through incoming links

A critical aspect of DOORS architecture is asymmetric storage.

Physical Storage #

  • Links are physically stored only in the source formal module
  • Link modules store the Linksets (the pairings), not the individual link instances between objects

This storage model means that:

  • You must have write permission in the source module to create or modify a link
  • You can always see outgoing links
  • You can only see incoming links if the source module is currently loaded into memory

Since links are stored in the source module, outlinks are always accessible.

Link l

for l in (current Object) -> "*" do {
    ...
}

The standard LinkRef loop only detects links for which the source module is already loaded.

To find all inlinks, including those from closed modules, you must first loop through the source references.

ModName_ srcModRef
LinkRef lr

// 1. Detect all source modules (even if closed)
for srcModRef in (tgtObject <- "*") do {

    // 2. Load the source module hidden (read mode) to make links visible
    read(fullName(srcModRef), false)
}

// 3. Now that sources are loaded, iterate through actual link references
for lr in tgtObject <- "*" do {
    ...
}

When looping through links in DXL, you can precisely control which relationships are traversed by specifying a Link Module name as a string in the loop syntax.

This acts as a filter, ensuring the interpreter only processes links governed by that specific module.

doors-concepts

The syntax for both outgoing and incoming link loops includes a string parameter for the link module.

SyntaxBehavior
"*"Iterates through all links regardless of the link module
"Analysis Links"Restricts the loop to links belonging only to that specific module

The Wildcard ("*") #

Using an asterisk as the module name tells DXL to iterate through all links, regardless of which link module they belong to.

Link l

for l in current -> "*" do {
    ...
}

Specific Module Name #

Providing the name of a link module restricts the loop to only those links.

If a Link Module Descriptor exists and is set to not overrideable, users may be forced to use that specific module for certain pairings.

Link l

for l in current -> "Analysis Links" do {
    ...
}

Syntax Examples #

This loop will only find links that point away from the source object through the "System Trace" link module.

Link l
Object srcObj = current

// Only iterate through links in "System Trace"
for l in srcObj -> "System Trace" do {
    ...
}

Similarly, when investigating incoming links (inlinks), you can ignore all other relationship types and focus solely on those arriving via a named module.

Note: For inlinks, the source module must be loaded for this specific loop to detect the links.

LinkRef lr
Object tgtObj = current

// Only iterate through incoming links in "Validation Links"
for lr in tgtObj <- "Validation Links" do {
    ...
}

Advantage #

Using specific module names in your loops is a best practice for:

  • performance,
  • readability,
  • and accuracy in large databases.

It prevents your script from accidentally processing irrelevant links such as:

  • "Change Proposal Links"
  • "Drafting Links"
  • temporary review links
  • or unrelated traceability paths.

Once you have a handle on a Link object in DXL, you can extract several pieces of metadata using specific functions.

FunctionDescription
source(l) / target(l)Returns the source or target object handle (if the module is loaded) or module reference
sourceAbsNo(l) / targetAbsNo(l)Returns the absolute number of the object at either end of the link
lastModifiedTime(l)Returns the date and time the link was last changed
l."Created By"Access attributes of the link itself using standard dot notation

While any user with write access can technically create a link module, Rational DOORS allows project managers to enforce strict linking rules at the folder or project level through Link Module Descriptors.

The Role of Descriptors #

A descriptor defines a mandatory or preferred link module for a specific pair of source and target modules.

  • Overrideable Flag: If a descriptor is set to not overrideable, users are forced to use the specified link module for that module pairing.
  • Mandatory Links: This setting ensures that links between the defined modules cannot be omitted during specific operations.

In DXL, you can programmatically manage these pairings using the addLinkModuleDescriptor and removeLinkModuleDescriptor functions.


Not all traceability exists within DOORS.

External Links provide a one-way relationship to resources outside the formal database, such as websites, files on a network, or other IBM Engineering tools.

  • One-Way Nature: Unlike internal links, no corresponding information is created in the target resource
  • DXL Handling: External links use the ExternalLink data type. You can iterate through them using specialized loops like for extLink in (Object o) <-> ""
  • OSLC Link Discovery: For modern integrations, DOORS uses a database-wide cache to store discovered OSLC links, improving performance when opening modules with many external dependencies

To DXL, a Link Module is a special container where each "Object" is actually a Linkset (a pairing definition).

Converting Objects to Linksets #

When looping through a Link Module, you must explicitly cast the object handle to a Linkset handle to access its properties.

Module lm = current // Assuming this is a Link Module
Object o
Linkset ls

for o in entire lm do {

    ls = linkset(o) // Explicit cast

    if (!null ls) {

        ModName_ targetMod = getTargetModule(ls)

        print "Linkset points to: " fullName(targetMod) "\n"
    }
}

Key Management Perms #

  • getTargetModule(ls) : The most reliable way to identify the destination module of a linkset definition
  • getSourceVersion(ls) : Retrieves version information for the source end of the linkset
  • side1(Module) / side2(Module) : Returns the objects currently selected on the source or target side of a visible link module matrix

Several practical DXL snippets for managing links, ranging from basic inspection to conditional cleanup.

This snippet counts all links for an object.

To ensure an accurate inlink count, it uses the source reference loop to detect links from modules that are currently closed.

Object o = current
int outCount = 0
int inCount = 0
Link l
ModName_ srcModRef

// Count outgoing links (always visible)
for l in o -> "*" do outCount++

// Count incoming links (must check all source references)
for srcModRef in o <- "*" do {

    // This loop identifies every source module, even if closed
    // We increment for each link found once the source is loaded
    if (read(fullName(srcModRef), false)) {

        LinkRef lr
        for lr in o <- "*" do inCount++
    }
}

print "Object " identifier(o) " has " outCount " Outlinks and " inCount " Inlinks.\n"

Links can have their own attributes (e.g., "Created By").

This script loops through an object’s outgoing links and prints:

  • the Link Module name,
  • the creator,
  • the modification time,
  • and the target information.
Object o = current
Link l

for l in o -> "*" do {

    // Get the handle of the Link Module governing this link
    Module lm = module(l)

    // Access link-level attributes using dot notation
    string creator = l."Created By"
    Date modTime   = lastModifiedTime(l)

    print "Link in Module: " (name lm) "\n"
    print "  Created By: " creator "\n"
    print "  Last Modified: " modTime "\n"
    print "  Target: " (targetAbsNo(l) "") " in " (fullName(target(l))) "\n"
}

This script deletes all outgoing links created by a specific user.

A link deletion only takes effect:

  • when the script finishes,
  • or when flushDeletions() is called.
Object o = current
Link l
string targetUser = "John Smith"

for l in o -> "*" do {

    if (l."Created By" == targetUser) {

        print "Deleting link to " (fullName(target(l))) "\n"
        delete(l)
    }
}

// Optional: force the deletion now
// flushDeletions()

To verify if a link already exists between two specific objects before creating a new one, use this pattern.

bool linkExists(Object src, Object tgt, string linkModName) {

    Link l

    for l in src -> linkModName do {

        if (targetAbsNo(l) == (tgt."Absolute Number") &&
            fullName(target(l)) == fullName(module(tgt))) {

            return true
        }
    }

    return false
}

// Usage
Object s = current
Object t = ... // some target object

if (!linkExists(s, t, "MyLinkModule")) {
    s -> "MyLinkModule" -> t
}

In a Link Module, every "Object" is actually a Linkset definition.

This snippet identifies linksets that no longer point to valid modules.

Module lm = current // Must be a Link Module
Object o
Linkset ls

for o in entire lm do {

    ls = linkset(o)

    if (!null ls) {

        ModName_ tgtMod = getTargetModule(ls)

        if (!exists(tgtMod)) {

            print "Found orphaned linkset definition for: " fullName(tgtMod) "\n"

            // delete(ls)
        }
    }
}

If you need to programmatically enforce that links between two modules must go through a specific Link Module, use Link Module Descriptors.

Folder f = current

string srcPath = "/Project/Source"
string tgtPath = "/Project/Target"
string linkMod = "/Project/LinkMod"

// Add a mandatory, non-overrideable link requirement
string err = addLinkModuleDescriptor(
    f,
    srcPath,
    tgtPath,
    false,
    true,
    linkMod,
    "Enforced Traceability"
)

if (!null err)
    print "Error: " err "\n"
else
    print "Link Descriptor added successfully.\n"