It's all about the answers!

Ask a question

Creating different type of links?


Soham Deb Maiti (16169) | asked Sep 16 '13, 5:03 a.m.
edited Sep 16 '13, 5:15 a.m. by Ralph Schoon (56.0k23642)
I have already one existing workitem with all types of links. I want to fetch all types of links from it and display. And I have to create similar links into another newly created WorkItem with some modifications. So basically i have 2 requirements-
1. Fetch and display all types of links of an IWorkItem.
2. Create all these types(fetched from point 1)of links into another new WorkItem.

I want to achieve this using Java Api for RTC.

4 answers



permanent link
Soham Deb Maiti (16169) | answered Sep 30 '13, 10:48 a.m.
Hi all,
         as mentioned earlier i have written the code where all these 14 types of linking is possible programmatically. But there are some flaws i found which i will also mention at the end.

/**
     * This method is to set Link between two workitems. Item_1 has the link
     * Item_2.
     *
     * @param objIWorkItem1
     * @param objIWorkItem2
     * @throws TeamRepositoryException
     * @throws URISyntaxException
     * @throws IllegalArgumentException
     */
    private boolean associateWorkItemToOtherWorkitem(IWorkItem objIWorkItem1,
            IWorkItem objIWorkItem2, String strSelectedType)
            throws TeamRepositoryException, URISyntaxException,
            IllegalArgumentException {
        boolean isLinkingSuccessfull = false;
        try {
            if (strSelectedType == null || strSelectedType.trim().isEmpty()) {
                // default case
                strSelectedType = "";
            }
            if (objIWorkItem1 == null || objIWorkItem2 == null) {
                System.out
                        .println("Both the WorkItems should be present for linking.");

                return false;
            }
            // process to associate links between two workitems. Item_1 has the
            // link Item_2.
            // handle1 fetched from WorkItem Item_1
            IWorkItemHandle handle1 = (IWorkItemHandle) objIWorkItem1
                    .getItemHandle();

            // handle2 fetched from WorkItem Item_2
            IWorkItemHandle handle2 = (IWorkItemHandle) objIWorkItem2
                    .getItemHandle();

            IWorkItemClient workItemClient = (IWorkItemClient) repo
                    .getClientLibrary(IWorkItemClient.class);

            IWorkItemWorkingCopyManager wcm1 = workItemClient
                    .getWorkItemWorkingCopyManager();
            wcm1.connect(handle1, IWorkItem.FULL_PROFILE, null);

            IWorkItemWorkingCopyManager wcm2 = workItemClient
                    .getWorkItemWorkingCopyManager();
            wcm2.connect(handle2, IWorkItem.FULL_PROFILE, null);

            WorkItemWorkingCopy workingCopy1 = wcm1.getWorkingCopy(handle1);

            WorkItemWorkingCopy workingCopy2 = wcm2.getWorkingCopy(handle2);

            // fetching reference(link) from WorkItem Item_2
            IReference objIreference2 = IReferenceFactory.INSTANCE
                    .createReferenceToItem(handle2);

            // fetching reference(link) from WorkItem Item_1
            IReference objIreference1 = IReferenceFactory.INSTANCE
                    .createReferenceToItem(handle1);

            // switch case of different types of links
            // Logic is like in WorkItem_1 the next item(WorkItem_2) is linked
            if (strSelectedType.trim().equalsIgnoreCase("Duplicate Of")) {

                // linking as "Duplicate Of"
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.DUPLICATE_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Children")) {
                // linking as Child to WorkItem_1. As there is restriction of
                // adding parent only, so adding WorkItem_1 as parent of
                // WorkItem_2
                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.PARENT_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference1);

            } else if (strSelectedType.trim().equalsIgnoreCase("Resolves")) {
                // linking as Resolves
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.RESOLVES_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Duplicated By")) {

                // linking as "Duplicated By".
                // As there is no support directly for "Duplicated By", so just
                // using the logic of "Duplicate Of" by reversing the Workitems,
                // which gives the same result.
                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.DUPLICATE_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference1);

            } else if (strSelectedType.trim().equalsIgnoreCase(
                    "Affects Plan Item")) {

                // linking as "Affects Plan Item"
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.AFFECTS_PLAN_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Depends On")) {

                // linking as "Depends On"
                // as there is no Linktype available for "Depends On", so used
                // "BLOCKS_WORK_ITEM" logic. But the workitems interchanged.
                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.BLOCKS_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference1);

            } else if (strSelectedType.trim().equalsIgnoreCase("Parent")) {
                // linking as Parent
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.PARENT_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Related")) {
                // linking as "Related"
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.RELATED_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase(
                    "Affected by Defect")) {

                // linking as "Affected by Defect"
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.AFFECTED_BY_DEFECT)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Tracks")) {
                // linking as Tracks
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.TRACKS_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase("Resolved By")) {

                // linking as "Resolved By"
                // as "Resolved By" not supported so by reversing the workitems
                // and using "Resolves" logic will do the same job.
                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.RESOLVES_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference1);

            } else if (strSelectedType.trim()
                    .equalsIgnoreCase("Contributes To")) {

                // linking as "Contributes To"
                // logic is exactly opposite to "Tracks". As there is no support
                // for "Contributes to" link directly so logic of "Tracks" only
                // used but workitems interchanged only.

                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.TRACKS_WORK_ITEM)
                                .getTargetEndPointDescriptor(), objIreference1);

            } else if (strSelectedType.trim().equalsIgnoreCase(
                    "Related Artifacts")) {
                // linking as "Related Artifacts"
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.RELATED_ARTIFACT)
                                .getTargetEndPointDescriptor(), objIreference2);

            } else if (strSelectedType.trim().equalsIgnoreCase(
                    "Related Work Items")) {
                // linking as "Related Work Items"
                // as there is no direct support of "Related Work Items", so
                // using the logic of "Related Artifacts" but just interchanging
                // the workitems.
                workingCopy2.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.RELATED_ARTIFACT)
                                .getTargetEndPointDescriptor(), objIreference1);
            }

            else {
                // all other cases
                System.out
                        .println("As no valid link type match available, so link has been done as 'TESTED_BY_TEST_CASE'.");
                // linking as TESTED_BY_TEST_CASE
                workingCopy1.getReferences().add(
                        ILinkTypeRegistry.INSTANCE.getLinkType(
                                WorkItemLinkTypes.TESTED_BY_TEST_CASE)
                                .getTargetEndPointDescriptor(), objIreference2);

            }

            workingCopy1.save(monitor);
            workingCopy2.save(monitor);

            System.out.println(objIWorkItem1.getId()
                    + " is successfully linked to (" + strSelectedType + ") "
                    + objIWorkItem2.getId());

            isLinkingSuccessfull = true;
        } catch (Exception e) {
            isLinkingSuccessfull = false;
        }

        return isLinkingSuccessfull;
    }

Findings/Flaws found-
1."Duplicate of" and "Duplicate by" links are vice versa. But these two links are getting created in reverse workitem.Needs more analyzing.
2.After creating these links by code, if opened Workitem is opened in Web Client, and tried to delete them, in that case errors are coming as "Null host..." or undefined uri. Not sure about the reason.This has been observed only for some links.

Comments
Ralph Schoon commented Sep 30 '13, 11:22 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

The issue with 2. is due to the fact that these are CLM links. You did not create them correctly. You can not put in a work item, you provide a location. See http://rsjazz.wordpress.com/2012/09/20/the-rtc-workitem-server-link-api-linking-to-work-items-and-other-elements/

        // get the location from the URI
        Location location = Location.location(uri);
        // resolve the item by location
        IAuditableCommon common = getService(IAuditableCommon.class);
        IAuditable referenced = common.resolveAuditableByLocation(
            location, ItemProfile.createFullProfile(
            location.getItemType()), null);





permanent link
Ralph Schoon (56.0k23642) | answered Sep 16 '13, 5:18 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER
Please have a look at http://rsjazz.wordpress.com/2012/10/20/following-calm-links-using-the-java-client-or-server-api/ and http://rsjazz.wordpress.com/2012/09/20/the-rtc-workitem-server-link-api-linking-to-work-items-and-other-elements/ and http://rsjazz.wordpress.com/2013/03/20/understanding-and-using-the-rtc-java-client-api/ .

Please be aware that you have to distinguish between work item links and CLM links for both, following and creating the links.

permanent link
Soham Deb Maiti (16169) | answered Sep 16 '13, 11:07 a.m.
@Ralph Schoon- Thank you very much for the help. Those links helped me a lot. But still I have some more issues. There are atlist 13 to 14 types of links like following.

"Duplicate Of"
"Children"
"Resolves"
"Duplicated By"
"Affects Plan Item"
"Depends On"
"Parent"
"Related"
"Affected by Defect"
"Tracks"
"Resolved By"
"Contributes To"
"Related Artifacts"


For all these different types of links, is there any common type of code which can be used to make that kind of link?
Like the following code snippent works for "Duplicate Of"  type and makes links of duplicates. But what for others? As I found that WorkItemLinkTypes does not provide constants for all these above mentioned 13 types of links.

workingCopy1.getReferences().add(ILinkTypeRegistry.INSTANCE.getLinkType(                           WorkItemLinkTypes.DUPLICATE_WORK_ITEM).getTargetEndPointDescriptor(), objIreference2);

It would be very helpfull if you could provide me some link/hint to achieve this.

permanent link
Ralph Schoon (56.0k23642) | answered Sep 16 '13, 12:18 p.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER
As far as I know there is no way to create links that works for all link types. But I don't know everything either.

The method described in https://rsjazz.wordpress.com/2012/09/19/the-rtc-workitem-link-api-linking-workitems-to-other-elements/ section Creating References Using WorkItemLinkTypes probably describes the most versatile approach. You have to distinguish between work item link types (parent, depends on) and CLM link types such as (tracks, links to test cases etc.). The difference is that the end point of the former are work items and the endpoints of the latter are URIReferences.

How you create these references is different. For the former you can use a work item, for the latter, you need to have or create a location. This is described in https://rsjazz.wordpress.com/2012/09/20/the-rtc-workitem-server-link-api-linking-to-work-items-and-other-elements/ section Creating References on the Server for the server. Server and client API are also slightly different. I'd suggest to gothrough the blogs and read them.

Please don't use ILinkServiceLibrary as described in https://rsjazz.wordpress.com/2012/09/20/the-rtc-workitem-server-link-api-linking-to-work-items-and-other-elements/ because it prevents the operational behavior to see the linkage.

Currently the CLM links are still created using this, which makes them not triggering advisors and such. I would suggest to read the posts and create a prototype to play around with this on a test server.



Comments
Soham Deb Maiti commented Sep 20 '13, 5:28 a.m.

As my requirement was to link between 2 WorkItems with all these possible link types...so I have gone through your second link-
This is described in https://rsjazz.wordpress.com/2012/09/20/the-rtc-workitem-server-link-api-linking-to-work-items-and-other-elements/ section Creating References on the Server
ln this link for method-  linkWorkItemsCLM() its mentioned the following line of code.

IStatus saveStatus = fWorkItemServer.saveWorkItem3(sourceWorkItem,
            targetReferences, null, null);
Now the question is, fWorkItemServer is the object of which class which has the method saveWorkItem3()?
 I feel its some local class which has been created for this method call and its not mentioned in that page. Please let me know if there is any other page/link which i missed to refer then please let me know and very sorry for writing all these.

By the way I am able to write the code for some of the link types...after completing i will post it here.


Ralph Schoon commented Sep 20 '13, 6:04 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

fworkitemServer is the IWorkItemServer service class.

        // Get the required service interfaces
        fWorkItemServer = getService(IWorkItemServer.class);
        fWorkItemCommon = getService(IWorkItemCommon.class);

I will update the post.

Your answer


Register or to post your answer.