The RTC WorkItem Client Link API – Linking to Work Items and Other Elements

It is sometimes interesting to follow links in work items. I have seen and answered several related questions at the Forum. This post is supposed to summarize what I have found about linking work items using the Plain Java Client Libraries so far. I will focus on the Client Library in this post because I realized that there are some important differences between the client and the server API with respect to accessing the work item’s references. I will try to address the differences on the server side in a later post. For now RTC Update Parent Duration Estimation and Effort Participant provides an example that shows how to follow work item to work item parent-child links on the server in an Advisor or in a Participant. In this case the information about existing and new references can be retrieved using the ISaveParameter.

*Update* The post A RTC WorkItem Command Line Version 2 contains downloadable code that performs most of the activities required for reading and modifying work items, including the creation of all kinds of links. The interesting code can be found in the package in the class WorkItemHelper. All techniques described below are used there. You can familiarize yourself with the concepts in this post and then look into that project for how it is used.

*Update* See the post Creating CLM Links With Back Link Between Work Items for some new information on CLM links betwen work items.

*Update* I figured the server side API and you can find the information in this post.

*Update* I took a deeper look at what to do with URI references.

*Update* See this link for code to get a work item handle from an URI

If you are just starting with extending Rational Team Concert, start reading this and the linked posts to get some guidance on how to set up your environment.

License and how to get started with the RTC API’S

As always, our lawyers reminded me to state that the code in this post is derived from examples from as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license, which basically means you can use it for internal usage, but not sell. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

You should be able to use the following code in this environment and get your own automation or extension working.

To keep it simple this example is, as many others in this blog, based on the Jazz Team Wiki entry on Programmatic Work Item Creation and the Plain Java Client Library Snippets. The example in this blog shows RTC Client and Common API.

Creating References Using WorkItemEndPoints

The following code shows the code used to create a reference to another work item. It is based on the WorkitemOperation code used in Uploading Attachments to Work Items. It can however be used also with any kind of WorkItemWorkingCopy saved with the WorkingCopyManager too.

The code shows the most basic way to create a reference in RTC using the client API.

 * Inner class to do the modification
private static class WorkItemReferencesModification extends WorkItemOperation {
	private IWorkItemHandle fOpposite;

	public WorkItemReferencesModification(IWorkItemHandle opposite) {
		super("Modifying Work Item References",IWorkItem.FULL_PROFILE);
		fOpposite = opposite;

	protected void execute(WorkItemWorkingCopy workingCopy, IProgressMonitor monitor) throws TeamRepositoryException {
		// Create a new reference to the opposite item
		IItemReference reference = IReferenceFactory.INSTANCE.createReferenceToItem(fOpposite);
		// Add the new reference using a specific work item end point
		workingCopy.getReferences().add(WorkItemEndPoints.BLOCKS_WORK_ITEM, reference);

This is the easiest way to create a reference from a work item to another work item. The code creates a new reference to a work item handle. In the second step it uses endpoints predefined in to create the reference. The endpoints of a reference, sort of, define the type of the reference. A reference is some kind of link between two objects. From the perspective of the objects the relationship might be different. For example a work item could have a parent from its perspective. The parent from its perspective would have a child. The relationship between two work items is defined using the endpoints from Both ends of the link have their own endpoint. By defining the opposite endpoint, the other endpoint is also determined.

When looking at the endpoints defined in WorkItemEndPoints it appears that the available endpoints are only for work item to work item links. Taking a closer look would reveal that even not all CLM work item to work item link types are available. In general there is no endpoint for any URL based relationship. You can only use this code if your link is based on these available WorkItemEndPoints.

Creating References Using WorkItemLinkTypes

If it is necessary to create other types of links for example to some URL this mechanism does not work. The code below shows an alternative approach that creates the endpoint using a more fundamental mechanism provided by using the

 * Inner class to do the modification
private static class WorkItemReferencesModification extends WorkItemOperation {

	private IWorkItemHandle fOpposite;

	public WorkItemReferencesModification(IWorkItemHandle opposite) {
		super("Modifying Work Item References",IWorkItem.FULL_PROFILE);
		fOpposite = opposite;

	protected void execute(WorkItemWorkingCopy workingCopy, IProgressMonitor monitor) throws TeamRepositoryException {
		// Create a new reference to the opposite item
		IItemReference reference = IReferenceFactory.INSTANCE.createReferenceToItem(fOpposite);
		// Create a new end point
		IEndPointDescriptor endpoint = ILinkTypeRegistry.INSTANCE.getLinkType(WorkItemLinkTypes.BLOCKS_WORK_ITEM).getTargetEndPointDescriptor();
		// Add the new reference using a specific work item end point
		workingCopy.getReferences().add(endpoint, reference);

The code uses the ILinkTypeRegistry and the WorkItemLinkTypes to create an endpoint and then creates the reference. This code is more flexible and allows more link types to be created. This includes links to elements using a URL such as OSLC links to elements in other OSLC providers. The code below would create a tested by test case link for a work item.

reference = IReferenceFactory.INSTANCE.createReferenceFromURI(new URI(""));

Accessing References

I am aware of two ways to access the references of a work item using the Client Libraries. If you have a WorkItemWorkingCopy you can access the references using this code:

// get all references from the work item workingcopy
IWorkItemReferences references = workingCopy.getReferences();

It is easy to get a working copy from a work item that already is derived from a working copy using

WorkItemWorkingCopy workingCopy = (WorkItemWorkingCopy) workItem.getWorkingCopy()

Another way to access the references, if you have a plain work item, is using the IWorkItemCommon client library. Note, in this case the ITeamRepository is required which can be retrieved using the method .getOrigin(). The IWorkItemClient client library provides this method as well, in case it is already available.

IWorkItemCommon common= (IWorkItemCommon) ((ITeamRepository)workItem.getOrigin()).getClientLibrary(IWorkItemCommon.class);
IWorkItemReferences references = common.resolveWorkItemReferences(workItem, null);

Once we have an IWorkItemReferences object we can analyze the references.

 * Analyze the references of a workitem
private void analyzeReferences(IWorkItemReferences references) {
	List endpoints = references.getTypes();
	for (IEndPointDescriptor iEndPointDescriptor : endpoints) {
		System.out.println("Endpoint: "
			+ iEndPointDescriptor.getDisplayName() + " ID: "
			+ iEndPointDescriptor.getLinkType().getLinkTypeId());
		List typedReferences = references.getReferences(iEndPointDescriptor);
		for (IReference iReference : typedReferences) {

The IWorkItemReferences provides all available link types for the contained references. The code above gets the list and iterates it to look at the references for each type. The code prints some information. The next step is to get all the references for a given endpoint and analyze each reference.

 * Analyze a reference
public void analyzeReference(IReference iReference) {
	if (iReference.isItemReference()) {
		Object resolvedRef = iReference.resolve();
	if (iReference.isURIReference()){

The code above checks each reference if it is a reference to an IItem for example an IWorkItem or an URI reference. For the item reference there is more to analyze so the code resolves it to get the object an passes it on. For an URI reference the code gets the URI and prints it.

The resolved object can now be analyzed in the code below. A cast is used to get to the contained element such as an IWorkItemHandle or a BuildResultHandle. Once the handle is available it is possible to use the ITeamreposiory.itemManager() to get the item from the handle and manipulate it.

 * Analyze an Item
private void analyzeItem(Object resolvedRef) {
	System.out.println(" Resolved item: "
		+ resolvedRef.toString());
	if(resolvedRef instanceof IWorkItemHandle){
		IWorkItemHandle handle = (IWorkItemHandle)resolvedRef;
	if(resolvedRef instanceof BuildResultHandle){
		BuildResultHandle handle = (BuildResultHandle)resolvedRef;

*Update* I looked deeper in what the client API provides in terms of accessing the elements referenced by the URI. Here is what I came up with. Please be aware that I am unsure if this works for all cases. It seems to be possible to resolve the element for example if it is in the same repository. If it is a work item you can then use the typical interfaces to access its data.

 * Further analyze an item referenced by an URI
 * @param iReference
public void analyzeReferenceTarget(IReference iReference) {
	URI uri = iReference.createURI();
	try {
		System.out.println("   Resolving URI: " + uri.toString());
		ITeamRepository teamRepo = (ITeamRepository) iReference.getLink().getOrigin();
		IAuditableClient auditableClient = (IAuditableClient) teamRepo.getClientLibrary(IAuditableClient.class);

		// get the location from the URI
		Location location = Location.location(uri);
		// resolve the item by location
		IAuditable referenced = auditableClient.resolveAuditableByLocation(location,
				ItemProfile.createFullProfile(location.getItemType()), null);
		// look for a referenced work item
		if (referenced instanceof IWorkItem) {
			IWorkItem referencedWI = (IWorkItem) referenced;
			System.out.println("   Resolved URI (resolve): "
				+ uri.toString() + " to: " + referencedWI.getId()  
				+ " " + referencedWI.getState2().toString());
	} catch (TeamRepositoryException e) {
	System.out.println("   Resolved URI: " + uri.toString());

This is pretty much the summary of how links work on the client. I hope the code is useful, and it is easy enough to enhance the code for other purposes. Please remember that there is few error handling at this point. You might want to enhance this.

Common API to create Link URI’s

If you want to provide a URI for elements such as work items, you can use the Location class to do so.

The following code creates two different URI’s for a work item that are used in different types of links.

IWorkItemCommon common = (IWorkItemCommon) teamRepository.getClientLibrary(IWorkItemCommon.class);

int id = new Integer(idString).intValue();
IWorkItem workItem = common.findWorkItemById(id,IWorkItem.SMALL_PROFILE, monitor);
if (workItem == null) {
	System.out.println("Work item: " + idString + " not found.");
	return false;

System.out.println("Work item: " + workItem.getId() + ".");
Location location = Location.namedLocation(workItem,((ITeamRepository) workItem.getOrigin()).publicUriRoot());
System.out.println("Named Location URI: " + location.toAbsoluteUri());
location = Location.itemLocation(workItem,((ITeamRepository) workItem.getOrigin()).publicUriRoot());
System.out.println("Item Location URI: " + location.toAbsoluteUri());

The named location looks something like


The item location looks something like


Different link types use the different locations for their endpoints. The API is common api and available in the client as well as the server.

48 thoughts on “The RTC WorkItem Client Link API – Linking to Work Items and Other Elements

  1. It’s really good stuff! Excellent!
    When I create links based on your code:
    I can create a link. But do you know how I can adding an “comment” into it? So the workitem will show the comment instead of the long URL.
    Thanks in advance

    • Hi,

      When you create the reference you can create that with a comment e.g. reference = IReferenceFactory.INSTANCE.createReferenceFromURI(fURI,”Some Comment”);
      Or IReferenceFactory.INSTANCE.createReferenceToItem(item, comment, extraInfo);

      There should be factories to create with comment and extra info for all these calls.

  2. I use this to do some grate things.
    when I use
    WorkItemWorkingCopy workingCopy = (WorkItemWorkingCopy) workItem.getWorkingCopy()

    My debuger replay :
    java.lang.ClassCastException: incompatible with

    what do I miss?
    Thanks in advance

    • I think I state that it is easy to get the workingcopy from the object if it was already a workingCopy. If you just have a work item, you need to get the working copy first using a workingcopy manager or service.

      This is from in the plain Java Examples:

      IWorkItemClient service = (IWorkItemClient) repo.getClientLibrary(IWorkItemClient.class);
      IWorkItemType workItemType = service.findWorkItemType(projectArea, “defect”, monitor);
      IWorkItemHandle handle = service.getWorkItemWorkingCopyManager().connectNew(workItemType, monitor);
      WorkItemWorkingCopy wc = service.getWorkItemWorkingCopyManager().getWorkingCopy(handle);
      IWorkItem workItem = wc.getWorkItem();
      try {
      List findCategories= service.findCategories(projectArea, ICategory.FULL_PROFILE, monitor);

    • Please note, that in my code the WorkItemOperation creates the workingcopy for me if it is called. So I would suggest to get the workingcopy as described in my answer before, if you don’t have one already.

  3. Hi,

    I’m trying to create a reference to a IBuildResult. I know how to do it manually, and found that the link type id is “”.
    I can’t find this one in WorkItemLinkTypes ok. But even if I try to create it manually it fails.

    ILinkTypeRegistry.INSTANCE.getLinkType(“”) returns null and ILinkTypeRegistry.INSTANCE.isRegistered(“”) false.

    Any idea ?

  4. Hi Ralph,
    I have link of snapshot to workitem using “Related Artifacts”. The link contains the URL of this snapshot.
    When trying to extract it from the link using the code above (auditableClient.resolveAuditableByLocation) I get an exception. Looks like that a “IWorkspaceConnection” is not an auditable.
    Any Idea?

  5. Hi Ralph,

    I have a changeset with a link to a workitem from a ‘friend’ provider, so the workitem is not found if I try to resolve it, do you know if there’s any server API to retrieve those ‘external’ objects? Just trying to resolve the work item, get some attributes but I get an ItemNotFoundException.

  6. Hi Ralph
    I would like using this link to create programmatically a CQ defect and link it to a RTC work Item
    I can create Defect by CQ rest api
    I can create a link to this URL using your example code
    but this link does not have the “hover” property that have a such link created using RTC-CQ bridge interface
    Maybe you have any idea why?


    • Hi Roger,

      I have not looked into this in detail. I would suggest to analyze links created with the bridge and try to figure how they have been created.

  7. Thank you for all the code you give to the community! I have many classes starting with Thank you Ralph and a link here…. 🙂

    Quick question: I am using this almost verbatim to create a simple link between an out of the box defect work item and a custom work item. Odd thing is, it only works if I put in the execute method (rtc 4.0.6). If I don’t do this, then I do not see the monitor output “Saving Work Item” nor does the link appear. I’m fine with that, I’m happy it’s working but was wondering if you might have an idea since I thought WorkItemOperation was supposed to take care of that.

    • That is odd. Here is code I used and I did not do a save:

      private static class LinkBlockingWorkItemOperation extends
      WorkItemOperation {

      private IWorkItemHandle fOpposite;

      public LinkBlockingWorkItemOperation(IWorkItemHandle opposite) {
      super(“Linking Blocking Work Item”, IWorkItem.FULL_PROFILE);
      fOpposite = opposite;

      protected void execute(WorkItemWorkingCopy workingCopy,
      IProgressMonitor monitor) throws TeamRepositoryException {
      IItemReference reference = IReferenceFactory.INSTANCE

  8. @rsjazz
    public void analyzeReferenceTarget(IReference iReference)

    if it is not work item and URI is referring for the Requirement or test case how to access the details of those artifacts ??

  9. @rsjazz I need one clarification
    currently I am using RTC Plain java libraries to fetch stories , Epics linked to task which is in turn linked to change set .So at the level of story i need to get info related to Test case and requirment. So at this level to fetch Test case and Requirement you are telling to use OSLC.

    Since i am new to OSLC programming my basic question is , is it possible to combine both RTC plain java program and OSLC program together(totally it should act as one application) ? .

    if you know any sample code where plain java and OSLC used together please give me link.Thanks in advance.

    • If you look into the RTC Plain Java Client Libraries, you see several Apache libraries. OSLC is HTTP/HTML which basically the RTC inner workings use as well. So yes, you can.

  10. @rsjazz
    Usecase is we wanted an OSLC link be created from ALM work item to Clearquest Record.
    By following the above line of code we are able to succeed.
    i need one clarification required,
    How is the Authentication happening to Clearquest side. Because if i manual try the usecase i should authenticate. Why i required this,
    When i try to run the code i get the below error,
    not authorised and not logged in to repository. But when open the same in web and authenticate to Clearquest and run the script ,things started working.
    How is this connected? Could you please answer this?

    • Sorry, I can’t answer this. I use it against one CLM server and in this case apparently you get cross certified. If you run against other servers, I assume you have to use apache to log into these other servers first. I have no example code for that. There might be code in the SDK.

    • I have no example for that and I wasn’t able to find one quickly either. It takes time to find this in the SDK and I basically don’t have that time.

    • In the workitem commandline. Remove the reference from the collection and save the work item with the new collection, I think. check the workitem commandline.

  11. @rsjazz
    I used the code “WorkItemReferencesModification” to implement “WorkItemLinkTypes.AFFECTED_BY_DEFECT”.
    It seems to work, but when i try to remove the link manually (only to check if everything worked), i had this message:
    java.lang.IllegalArgumentException: Host name may not be null


    • This is a symptom of one of the following two issues
      1. Wrong direction of the link ends
      2. The Reference was created in the wrong way.

      For 2. there are multiple ways how the URIs are created. Work Item Link types and location or item based link types.

      Location location = Location.location(uri); is for location types. You have to look what types the relationship needs by looking at an example that was created by the tool and then you have to create the link accordingly.

    • First al thanks for the answer, it was very helpfull to understand what it was wrong.
      So with this class:
      private class LinkTrackingWorkItemOperation extends WorkItemOperation {
      private IWorkItem fOpposite;
      private IEndPointDescriptor fIEndPointDescriptor; // The endpoint to use
      public LinkTrackingWorkItemOperation(IEndPointDescriptor iEndPointDescriptor, IWorkItem opposite) {
      super(“Modifying Work Item References”,IWorkItem.FULL_PROFILE);
      fOpposite = opposite;
      protected void execute(WorkItemWorkingCopy workingCopy, IProgressMonitor monitor) throws TeamRepositoryException {
      IWorkItemClient workItemClient = (IWorkItemClient) teamRepository.getClientLibrary(IWorkItemClient.class);
      URI myURI = ItemURI.createWorkItemURI(workItemClient.getAuditableCommon(), fOpposite.getId());
      Location location = Location.location(myURI);
      IReference targetEndpoint = IReferenceFactory.INSTANCE.createReferenceFromURI(location.toAbsoluteUri());

      I can call with:
      LinkTrackingWorkItemOperation operation = new LinkTrackingWorkItemOperation(
      ILinkTypeRegistry.INSTANCE.getLinkType( WorkItemLinkTypes.AFFECTED_BY_DEFECT).getTargetEndPointDescriptor(), wi);

      thanks again

  12. IWorkItem workItem = workItemClient.findWorkItemById(783, IWorkItem.FULL_PROFILE, null);
    IItemManager itm = teamRepository.itemManager();
    List history = itm.fetchAllStateHandles((IAuditableHandle) workItem.getStateHandle(), null);
    for(int i = history.size() -1; i >= 0; i–){
    IAuditableHandle audit = (IAuditableHandle) history.get(i);
    IWorkItem workItemPrevious = (IWorkItem) teamRepository.itemManager().fetchCompleteState(audit,null);

    now how can i fetch the Change Request type by using workItemPrevious ?

    • In the field on the top right underneath the banner picture and before the button called Search, type “attachment” and then press the Search button.

      Thank you very much.

      • public void run(AdvisableOperation operation, IProcessConfigurationElement participantConfig,IAdvisorInfoCollector collector, IProgressMonitor monitor )
        throws TeamRepositoryException
        Object data = operation.getOperationData();
        ISaveParameter saveParameter = null;
        IWorkItemReferences WIReferences = null;
        List references = new ArrayList();

        if(data instanceof ISaveParameter){
        saveParameter = (ISaveParameter) data;

        IWorkItem newWorkItem = (IWorkItem) saveParameter.getNewState();
        IWorkItemServer workItemServer = getService(IWorkItemServer.class);
        WIReferences = workItemServer.resolveWorkItemReferences(newWorkItem, monitor);
        references = WIReferences.getReferences(WorkItemEndPoints.ATTACHMENT);
        for (IReference iReference : references) {
        IAttachmentHandle attachHandle = (IAttachmentHandle) iReference.resolve();

        IAuditableCommon common = getService(IAuditableCommon.class);
        IAttachment attachment = (IAttachment) common.resolveAuditable(attachHandle, IAttachment.DEFAULT_PROFILE, null);

        If the attachment is a xlsx file,
        How to parse its content?
        Is there any library to help me?


      • No, RTC does not have any APIs for specific file types that I would know about.

        Java has basic APIs to read files, anything else is up to you.

  13. Hello Ralph, thanks for the wonderful tutorial.

    I’m trying to create a link with almost similar code

    IItemReference reference = IReferenceFactory.INSTANCE.createReferenceToItem(srcWorkItem);
    wc.getReferences().add(WorkItemEndPoints.TRACKS_ITEMS, reference);

    1. The above code doesn’t create a link unless I call;
    2. After calling I see that the link is created successfully. But I also see a URL pop up in the Web interface as “Refresh to get the latest updates.” for every single click I make in the web page even though nothing has changed in the work item after creation of the link. Can you please tell me what I’m missing here.

    • What do you mean, nothing changed on the work item. You added a link and you saved it, what would you expect?

      1. As mentioned in several posts and examples you have to save work items to perform the change.
      2. Any change that is performed to a work item creates a potential conflict for users that have the work item open in an editor, so the work item shows the fact the data is stale and warns the user

      • 2. I understand that the refresh link appears when some attributes have changed in the workitem. But the same refresh pop up keeps appearing as I navigate through the page even though no changes had been made by me or else where to the same work item.

      • The link indicates any change. An added link is a change. Unless you refresh, the link should show up.

        I am not sure but I might remember I might have seen a case where this came up when creating links and a refresh did not fix it. If so, that was likely because I got the links wrong. e.g. put the wrong object on the wrong end, use an illegal Location/ItemType.

        I am afraid that I can not help with things like this really. I provide the examples based on experience I made. I only have a certain amount of experience.

  14. IWorkItemType workItemType = (IWorkItemType) teamRepository.getClientLibrary(IWorkItemType.class);


    ICategoryHandle iCategoryhandler =(ICategoryHandle) teamRepository.getClientLibrary(ICategoryHandle.class);

    both of these are showing null values when printing it into the console.

    How to get these two instances.
    Please help me with this
    I am trying to create a Defect using java code with the supported api’s in Jazz server.

    • Please read through the getting started and the related posts. There are enough examples how to create work items.

      None of the classes you use up there are client libraries. Read the posts to understand client libraries.

  15. Hi Ralph,
    we’re using the to find links but in 6.0.6 it is deprecated. I can’t find any documentation about it, do you know where it is or how it is handled in new versions?

    Best regards,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.