Main Content

Use Command-Line API to Update or Repair Requirements Links

This example covers a set of standard situations when links between design artifacts and requirements become stale after one or more artifacts are moved or renamed. Rather then deleting broken links and creating new ones, we want to update existing links so that creation/modification history and other properties (description, keywords, comments,..) are preserved.

Example Project Files

Before you begin, ensure a clean initial state by running slreq.clear command. Then open the CruiseRequirementsExample project. This will unzip a collection of linked artifact files into a new subfolder under your MATLAB/Projects folder.

slreq.clear
openProject("CruiseRequirementsExample");

Simulink Model Linked to Requirements

We will focus on a small part of this Project's Dependency Graph: open the crs_plant.slx Simulink® model, that has several links to an external Microsoft® Word document crs_reqs.docx.

open_system('crs_plant');

Navigate one of the links to open the linked document.

rmi('view', 'crs_plant/status', 1);

Word document opens to the corresponding section:

Here is how to use command-line APIs and check for links from crs_plant.slx to crs_reqs.docx.

linkSet = slreq.find('type', 'LinkSet', 'Name', 'crs_plant');
links = linkSet.getLinks();
disp('Original Links to Word document:');
Original Links to Word document:
for i = 1:numel(links)
    linkTarget = links(i).getReferenceInfo();
    if contains(linkTarget.artifact, 'crs_req.docx')
        source = links(i).source;
        disp(['    found link from ' strrep(getfullname([bdroot source.id]),newline,'') ...
            ' to crs_req.docx']);
    end
end
    found link from crs_plant/Vehicle1/vehiclespeed to crs_req.docx
    found link from crs_plant/throttDrv to crs_req.docx
    found link from crs_plant/status to crs_req.docx
    found link from crs_plant/throttleCC to crs_req.docx

Navigation of Direct Links in the Presence of Imported References

Open the Requirements Editor by entering slreq.editor at the MATLAB® command line. You will see two Requirement Sets loaded: crs_req.slreqx and crs_req_func_spec.slreqx. The first Requirement Set is a collection of references imported from crs_req.docx, and the second was manually created in the Requirements Editor. If you now close the Word document and navigate the same link from crs_plant/status Inport block, the corresponding imported reference is highlighted in the Requirements Editor, because navigation action finds the matching reference in a loaded imported Requirement Set.

updatelinks_importOriginal.png

You can still use the Show in document button to see the linked Requirement in the context of original document.

slreq.editor();
rmidotnet.MSWord.application('kill');
rmi('view', 'crs_plant/status', 1);

Use Case 1: Batch-Update Links After Document Renamed

Suppose that an updated version of the requirements document is received, named crs_req_v2.docx. We now want the links in crs_plant.slx to target the corresponding sections of the updated document. For the purpose of this example, we will make a copy of the original document in same folder with a modified name. We then use slreq.LinkSet API to batch-update all links in a given LinkSet to connect with the newer copy of the document:

copyfile(fullfile(pwd, 'documents/crs_req.docx'), fullfile(pwd, 'documents/crs_req_v2.docx'));
linkSet.updateDocUri('crs_req.docx', 'crs_req_v2.docx');

Verify the Update of Matching Links

Now we can navigate the same link and confirm that the appropriate version of the external document opens. If we iterate all links as before, this confirms that all 4 links updated as intended:

rmi('view', 'crs_plant/status', 1); % updated document opens
links = linkSet.getLinks();
disp('Links to Word document after update:');
Links to Word document after update:
for i = 1:numel(links)
    source = links(i).source;
    linkTarget = links(i).getReferenceInfo();
    if contains(linkTarget.artifact, 'crs_req.docx')
        warning(['link from ' source.id ' still points to crs_req.docx']);  % should not happen
    elseif contains(linkTarget.artifact, 'crs_req_v2.docx')
        disp(['    found link from ' strrep(getfullname([bdroot source.id]),newline,' ')...
            ' to crs_req_v2.docx']);
    end
end
    found link from crs_plant/Vehicle1/vehicle speed to crs_req_v2.docx
    found link from crs_plant/throttDrv to crs_req_v2.docx
    found link from crs_plant/status to crs_req_v2.docx
    found link from crs_plant/throttleCC to crs_req_v2.docx

Navigate to Imported References After Updating Links

As demonstrated above, when imported references are available in the Requirements Editor, navigating a link will select the matching reference object. However, we have just updated links for a new version of the document crs_req_v2.docx, and there are no imported references for this document. Navigation from Simulink blocks in the presence of the Requirements Editor brings you directly to the external Word document.

To avoid this inconsistency we need to update the previously imported references for association with the updated document name. We use the slreq.ReqSet API to accomplish this task. Additionally, because the updated document may have modified Requirements, we must use updateFromDocument API to pull-in the updates for reference items stored on Requirements Toolbox side. After this is done, navigating from Simulink model will locate the matching imported reference.

updatelinks_importOriginal.png

Find the Requirement Set with imported references. Update the source file location and find the top-level Import node.

reqSet = slreq.find('type', 'ReqSet', 'Name', 'crs_req');
reqSet.updateSrcFileLocation('crs_req.docx', 'crs_req_v2.docx'); 
importNode = reqSet.find('CustomId', 'crs_req_v2');

Update the imported references from the source file. Close Microsoft Word. Then, navigate to the updated reference in the Requirements Editor.

importNode.updateFromDocument();
rmidotnet.MSWord.application('kill');
rmi('view', 'crs_plant/status', 1);

Cleanup After Use Case 1

Discard link data changes to avoid prompts on Project close. Close the project (also cleans-up MATLAB path changes). Close Microsoft Word.

slreq.clear();                        
prj = simulinkproject(); prj.close();
rmidotnet.MSWord.application('kill'); 

Use Case 2: Batch-Update Links to Fully Rely on Imported References

As demonstrated in Use Case 1 above, additional efforts are required to maintain "direct links" to external documents when documents are moved or renamed. A better workflow is to convert the existing "direct links" into "reference links", which are links that point to the imported References in *.slreqx files and no longer duplicate information about the location or name of the original document. When using this option, the external source document association is stored only in the Requirement Set that hosts the imported References.

To demonstrate this workflow, restart from the same initial point by reopening the CruiseRequirementsExample project in a new subfolder. Copy the Simulink model to your directory and open it.

openProject("CruiseRequirementsExample");
copyfile(fullfile(pwd, 'documents/crs_req.docx'), fullfile(pwd, 'documents/crs_req_v2.docx'));
open_system('crs_plant');

Find the crs_plant link set and crs_req requirement set with imported References.

linkSet = slreq.find('type', 'LinkSet', 'Name', 'crs_plant');
reqSet = slreq.find('type', 'ReqSet', 'Name', 'crs_req');

We then use slreq.LinkSet API to update all the direct links in crs_plant.slmx. Then create an array of all the links in the link set.

linkSet.redirectLinksToImportedReqs(reqSet);
links = linkSet.getLinks();

After updating the LinkSet in this way, loop over all the links to confirm the absence of "direct" links to crs_req.docx file.

disp('Check for links to original external document:');
Check for links to original external document:
counter = 0;
for i = 1:numel(links)
    linkTarget = links(i).getReferenceInfo();
    if contains(linkTarget.artifact, 'crs_req.docx')
        source = links(i).source;
        warning(['link from ' source.id ' still points to crs_req.docx']);
        counter = counter + 1;
    end
end
disp(['    Total ' num2str(counter) ' links to external document']);
    Total 0 links to external document

Navigate from the Simulink model to the updated reference.

rmi('view', 'crs_plant/status', 1);

Links to References and External Document Rename

Now, when all links point to imported References and not to the external document, traceability data remains consistent after document rename, as long as the Import node is updated for the new external document name. As in the Use Case 1, we will pretend there is an updated version of the external requirements document, by resaving our Word document with a new name. We then perform the required update for the Import node by using the same APIs as before. Now, because the links rely on imported References, and do not store information about imported document, navigation from Simulink model brings us to the updated reference, same as after performing all the steps of Use Case 1.

updatelinks_importOriginal.png

The Reference is now associated with the updated external document, [Show in document] button opens the updated (renamed) document, and no further adjustment on the LinkSet side is required.

Find the Requirement Set with imported references. Update the source file location and find the top-level Import node.

reqSet = slreq.find('type', 'ReqSet', 'Name', 'crs_req');
reqSet.updateSrcFileLocation('crs_req.docx', 'crs_req_v2.docx'); 
importNode = reqSet.find('CustomId', 'crs_req_v2');

Update the imported references from the source file. Then, navigate to the updated reference in the Requirements Editor.

importNode.updateFromDocument();
rmi('view', 'crs_plant/status', 1);

Cleanup After Use Case 2

Discard link data changes to avoid prompts on Project close. Close the project (also cleans-up MATLAB path changes). Close Microsoft Word.

slreq.clear();                        
prj = simulinkproject(); prj.close();
rmidotnet.MSWord.application('kill'); 

Use Case 3: Moving Linked Artifacts to a New Project

Now suppose that we are branching an existing project with linked artifacts, and we need to create a new set of renamed artifacts with all the traceability links as in the original Project. As before, we will extract the CruiseRequirementsExample project into a new subfolder, and convert the "direct links" to "reference links", as we have done in Use Case 2 above. We then go ahead and create "new versions" of the linked artifacts by resaving each one with the _v2. name.

After creating renamed copies of Simulink model, the imported external document, and the Requirement Set with the imported Requirements, there is one problem: renamed model is linked to the references in the original Requirement set, not in the renamed Requirement set. In the Details pane, under Links, the links appear unresolved because the original model is not loaded.

updatelinks_oldReference.png

Open the CruiseRequirementsExample project and open the crs_plant model. Find the link set for crs_plant and the requirement set crs_req.

openProject("CruiseRequirementsExample");
open_system('models/crs_plant.slx');
linkSet = slreq.find('type', 'LinkSet', 'Name', 'crs_plant');
reqSet = slreq.find('type', 'ReqSet', 'Name', 'crs_req');

Convert the direct links to reference links. Create renamed copies of the files and save them.

linkSet.redirectLinksToImportedReqs(reqSet);     
mkdir(fullfile(pwd, 'copied'));
save_system('crs_plant', fullfile(pwd, 'copied/crs_plant_v2.slx'));  
reqSet.save(fullfile(pwd, 'copied/crs_req_v2.slreqx'));              
copyfile('documents/crs_req.docx', 'copied/crs_req_v2.docx');        

Associate the renamed requirement set with the renamed document. Find the top level Import node.

reqSet.updateSrcFileLocation('crs_req.docx', fullfile(pwd, 'copied/crs_req_v2.docx'));
importNode = reqSet.find('CustomId', 'crs_req_v2');

Ensure the contents in the renamed requirement set match the contents of the renamed document by updating the imported References. Navigate from the renamed Simulink model to the item in the renamed requirement set. The old item in the original requirement set is highlighted, which is incorrect.

importNode.updateFromDocument();
rmi('view', 'crs_plant_v2/status', 1);

Update Links in Renamed Source to Use the Renamed Destination as the Target

Similarly to Use Case 1, we can use LinkSet.updateDocUri(OLD, NEW) API to update links in crs_plant_v2.slmx to use the renamed Requirement Set crs_req_v2.slreqx as the link target, instead of the original crs_req.slreqx. Once this is done, navigate again from the block in the renamed model. The requirement in the renamed Requirement Set is selected, and the links in the Details pane under Links at bottom-right are resolved.

updatelinks_updatedReference.png

Find the link set for the new copy of the model, crs_plant_v2. Update the name of the requirement set linked with the new copy of the model. Navigate from the renamed Simulink model to the item in the renamed requirement set. This time, it highlights the correct item.

linkSet = slreq.find('type', 'LinkSet', 'Name', 'crs_plant_v2');
linkSet.updateDocUri('crs_req.slreqx', 'crs_req_v2.slreqx');
rmi('view', 'crs_plant_v2/status', 1);