Jazz Library Creating, customizing, and deleting approval records programmatically with Rational Team Concert
Author name

Creating, customizing, and deleting approval records programmatically with Rational Team Concert

Summary

In Rational Team Concert (RTC), the review process of a work item can be achieved with approval records. These can be created in a work item manually. But manual intervention becomes challenging and expensive when the data is in bulk. For instance, if there is data from any other source system containing approval information which needs to be migrated to RTC, or if there is a custom integration between a third party system and RTC, which might require the creation of approval records periodically based on certain triggers in the source system. This could be successfully achieved through the RTC API. This article explains how to use RTC API to create, customize, and delete approval records in RTC programmatically.

Overview

RTC is a Jazz based product integrating and collaborating various tasks such as work item tracking, Ssurce code management, iteration planning, and continuous builds. It offers various capabilities so that it can be integrated as desired by the team to achieve the common goal more efficiently, and thus increasing their productivity. RTC achieves this task through the interaction of Project Areas, Streams, Components and Work Items. RTC also provides review, approval and verification processes for it’s work items. This process is followed by approval records found in work item’s approval tab.

Approval records, if mandated on work items, can require a user to either accept or reject the record based on some user desired condition. For example, the state transitioning of the work item. When a user tries to save a work item that requires an approval for a state transition, and the work item is not approved, the save operation fails and a message is displayed in the Team Advisor View. Similarly, through the approval tracking section in project configuration, the user can control the workflow of the work item through approvals. You can find more details on this in the “More Information” section at the end of this article.

Creating/Customizing Approval records through the UI

There is an approval tab on the Work Item where you can create approval records with 3 predefined types. Approvals are set with a due date corresponding to which email notification will be sent to all approvers to complete their review process. Constant reminders are sent once the approval due date has elapsed.
Process to create an approval record:

  1. Create/Open an existing Work Item and navigate to the Approval tab at the bottom panel of the work item.
  2. On the right hand side of the Approvals tab we can see various options: New approval, Edit approval, Add approver, Edit state, Remove and Add comment.
  3. Click on New approval button to create a new approval record for the work item.
  4. The first entry Type has 3 predefined values in RTC – Approval, Review and Verification. Approval corresponds to the approval process of the work item along with it’s change sets. Review corresponds to the review process of work item and Verification corresponds to verifying the work item and its relative change sets. Let’s create a Review type approval record.
  5. The second entry is the subject of the approval record and can be any user defined string, for instance “Code Review”
  6. The third entry is the due date of the approval record.
  7. The last entry corresponds to adding the approver name to the approval record. The user needs to be either imported or created in the RTC repository in order to add them as an approver.
The following screen shot shows the approval record screen:

Screen shot of approval record window

Figure: Approval Record UI creation

Once all the required entries are filled, click OK to create the approval record. Please remember you need to save the work item in order to save the approval record just created. This will attach the newly created approval record to the work item as shown below:

Screen shot of approval record attached to work item

Figure: Approval Record attached to work item in approvals tab

You can see that the state of the newly created approval record is automatically set to Pending. This is the default state for any newly created approval record. Other valid states are Approved and Rejected.

Process to customize/delete an existing approval record:

  1. Existing approval records can be customized/removed from a work item by: Edit approval, Add approver, Edit state, Remove.
  2. To edit an existing approval record, select the approval record and click Edit approval. The approval record window (as shown above) will pop up and the user can now change the type, subject, due date, add additional approvers or remove existing approver.
  3. In case the user only wants to add a new approver, he can achieve this by just clicking the Add approver button.
  4. In case of a state change user can click Edit State and can change it to Approved/Rejected.
  5. In case of a deletion, click the required approval record and click Remove to delete the record
Multiple approval records can be created for a work item.

Manual creation of approval records are helpful only when there is a small limited number of work items whose approvals needs to be created. This situation becomes challenging in case there needs to be mass updation of approval records or there is a custom integration between a third party system and RTC which might need creation of approval records on periodic basis. RTC provides an Item connector framework that supports this synchronization between objects across the repositories. But currently there is no support in RTC for customization of approval records in this framework. Thus we will be using RTC API’s to extend the approval process.

Benefits of creating/customizing approval records programmatically

The above mentioned UI challenges can be overcome by programmatic creation/customization of approval records via RTC API’s. The benefits achieved by the API approach are:
  • Creation/customization of larger volume of approval records can be achieved easily.
  • Data from other source system can be easily migrated to RTC.
  • Custom integrations are possible with RTC and user based requirement approval records can be generated periodically or based on user defined triggers

Detailed programmatic solution for creating/customizing approvals

Approval records consists of following attributes:
  1. Type
  2. Subject
  3. Due Date
  4. State
  5. Approver

State is inserted once the record is created. Type and Subject are the two mandatory attributes required to create approval records. To create approval records programmatically we need to set these attributes to the desired values generally known as approval descriptors.

We will be using the following RTC API’s, which are in package com.ibm.team.workitem.common.model, to achieve this:

IApproval

IApprovalDescriptor

IApprovals

Programmatic Creation of Approval Record

  1. To create approvals in RTC, we will first get all the required Client Libraries:
      private static void loadClient(final ITeamRepository teamRepository) {  	  IAuditableClient auditableClient = (IAuditableClient)teamRepository.getClientLibrary(IAuditableClient.class);  IWorkItemClient workitemClient = (IWorkItemClient)teamRepository.getClientLibrary(IWorkItemClient.class);  IQueryClient queryClient = (IQueryClient) teamRepository.getClientLibrary(IQueryClient.class);	    }  
  2. Creating approvals is mainly executed by following two methods of IApprovals class:
    • IApprovalDescriptor createDescriptor(String typeIdentifier, String name);
    • IApproval createApproval(IApprovalDescriptor descriptor, IContributorHandle approver);
  3. We will first need to create a descriptor. The createDescriptor method creates an approval descriptor with the typeIdentifier and name. Here typeIdentifier is the type attribute of the approval record, and the name is Subject to be given for the approval. The initial state of the descriptor is pending. This descriptor is then passed to createApproval() method along with the contributor handle of the approver, which creates and then returns the approval. Here we are setting the type of approval as review.

    String approvalType = WorkItemApprovals.REVIEW_TYPE.getIdentifier();  approvalDescriptor= approvals.createDescriptor(approvalType, "Code Review ");     approval = approvals.createApproval(approvalDescriptor, approver);
  4. We now need to fetch the required work item to which we want to add this approval. This can be achieved by querying the project area with the respective work item attribute ID.
      public static IWorkItem fetchWorkItemById(ITeamRepository teamRepo, IProjectArea projArea,String workItemId) throws TeamRepositoryException {    loadClient(teamRepo);    final IQueryableAttributeFactory factory = QueryableAttributes.getFactory(IWorkItem.ITEM_TYPE);    final IQueryableAttribute attributeID = factory.findAttribute(projArea,"id", auditableClient, null);    final Expression attributeExpression = new AttributeExpression(attributeID, AttributeOperation.EQUALS, workItemId);    final IQueryableAttribute att = factory.findAttribute(projArea,IWorkItem.PROJECT_AREA_PROPERTY, auditableClient, null);    final Expression expression = new AttributeExpression(att,AttributeOperation.EQUALS, projArea);    final Term term = new Term(Operator.AND);    term.add(expression);    final Term term3 = new Term(Operator.AND);    term3.add(attributeExpression);    term.add(term3);    final IQueryResult<IResolvedResult<IWorkItem>> result = queryClient.getResolvedExpressionResults(projArea, term, IWorkItem.DEFAULT_PROFILE);    if (result.hasNext(null)) {  	final IResolvedResult<IWorkItem> resolved = result.next(null);  		return resolved.getItem();  	}  	return null;  }  
  5. We now have a reference for the work item. In order to change any attribute of the work item, we need to fetch its working copy through IWorkItemClient and then extract its approvals. We have already shown above how to create an approval descriptor so as to create approvals with required properties through createDescriptor(). We need to pass this descriptor and create the approval by calling createApproval() on the approvals (extracted from the work item), and passing the descriptor and approver. At the end, we will add this approval to the Work Item approvals and save the working copy of the work item in order to attach the newly created approval record to the work item.

    Let’s say the work item we want to add approvals to has the id “42”.
      public void createApprovals(final ITeamRepository teamRepository, IProjectArea projArea, String user_number){    IContributor approver = fTeamRepository.contributorManager().fetchContributorByUserId(user_number,null);    IWorkItemWorkingCopyManager mgr = workitemClient.getWorkItemWorkingCopyManager();    IWorkItem workItem = fetchWorkItemById(teamRepository,projArea,'42');    mgr.connect(workItem, IWorkItem.FULL_PROFILE, null);    WorkItemWorkingCopy copy = mgr.getWorkingCopy(workItem);  			  IApprovals approvals = copy.getWorkItem().getApprovals();    // WorkItemApprovals.REVIEW_TYPE.getIdentifier corresponds to Workitem approver of type Review   String appType = WorkItemApprovals.REVIEW_TYPE.getIdentifier();    IApprovalDescriptor approvalDescriptor = approvals.createDescriptor(appType, "Code Review for work Item 42");     IApproval approval = approvals.createApproval(approvalDescriptor, approver);    approvals.add(approval);    copy.save(null);    mgr.disconnect(workItem);  }  

The newly created approval can be seen by refreshing the work item as below:

Updated approval record

Figure : Updated approval record

Customization of approval records through API

Approval records can be customized through API. The following are the properties of an approval record:
  • cumulativeStateIdentifier holds the state of the approval
  • name property holds the content name of the approval (Subject)
  • typeIdentifier holds the type of the approval.
  • approver holds the user who needs to approve the approval
  • dueDate holds the end date of an approval to be accepted/rejected from the approver
Except for changing the state (i.e. cumulativeStateIdentifier) and approver of the approval, all of the above mentioned properties can only be changed by updating the approval descriptor of the approvals.

Customizing typeIdentifier, name and dueDate

Again, as already explained in the create approval section, the user first needs to get the reference of the work item and fetch approvals from it. Since these attributes can only be set on the approval descriptors, we need to fetch the approval descriptors of approvals. It will return a list of approval descriptors iterating over which we can set the required attributes to approval descriptor. In code below, we are updating the name/subject of the approval in case the desired string is matched.
  public void customizeApprovals(final ITeamRepository teamRepository, IProjectArea projArea){    IWorkItemWorkingCopyManager mgr = workitemClient.getWorkItemWorkingCopyManager();    IWorkItem workItem = fetchWorkItemById(teamRepository,projArea,'42');    mgr.connect(workItem, IWorkItem.FULL_PROFILE, null);    WorkItemWorkingCopy copy = mgr.getWorkingCopy(workItem);  			  IApprovals approvals = copy.getWorkItem().getApprovals();    final List<IApproval> approvalList = approvals.getContents();    final Iterator<IApproval> it = approvalList.iterator();    while (it.hasNext()) {    IApproval approval = it.next();    if (approval.getDescriptor().getName().equals("Code Review for work Item 42")     {  	approval.getDescriptor().setName("Reviewing code for work Item 42");    }  }  copy.save(null);    mgr.disconnect(workItem);  }  
Similarly, the approval typeIdentifier and dueDate can also be updated. Please note: typeIdentifier and cumulativeStateIdentifier can only be updated with the predefined types and states available in RTC. User defined types and states are not yet supported in RTC.

Customizing cumulativeStateIdentifier of approval

Customizing cumulativeStateIdentifier or state of approval is relatively straightforward as it can be done directly on approval and doesn’t involve extracting and updating the approval descriptor. Currently we have 3 states for approvals which can be represented as below:
  private static final String PENDING = "com.ibm.team.workitem.approvalState.pending";  private static final String REJECTED = "com.ibm.team.workitem.approvalState.rejected";  private static final String APPROVED = "com.ibm.team.workitem.approvalState.approved";  

Code snippet shown below will get the reference of the work item and fetch approvals from it. Approvals list will be searched for all the approvals having state as pending and will update the state as approved.

  public void updateApprovalState(final ITeamRepository teamRepository, IProjectArea projArea){    IWorkItemWorkingCopyManager mgr = workitemClient.getWorkItemWorkingCopyManager();    IWorkItem workItem = fetchWorkItemById(teamRepo,projArea,'42');    mgr.connect(workItem, IWorkItem.FULL_PROFILE, null);    WorkItemWorkingCopy copy = mgr.getWorkingCopy(workItem);  			  IApprovals approvals = copy.getWorkItem().getApprovals();    final List<IApproval> approvalList = approvals.getContents();    final Iterator<IApproval> it = approvalList.iterator();    while (it.hasNext()) {    IApproval approval = it.next();    if(approval.getStateIdentifier().equalsIgnoreCase("Pending")){        approval.setStateIdentifier(APPROVED);       }  }  copy.save(null);    mgr.disconnect(workItem);  }  

Customizing approver of approval and deleting approvals

As of today there is no direct way to customize approver from API. We can fetch the approver directly from approval but we cannot set it.

The workaround to this problem is to fetch the approvals, get the contents of approval descriptor, remove the approval from the work item, create a new approval descriptor containing the contents of the descriptor already fetched along with new approver, adding and saving them to the approvals of the work item.
  public void deleteAndUpdateApprover(final ITeamRepository teamRepository, IProjectArea projArea,String user_number){    IContributor newApprover = fTeamRepository.contributorManager().fetchContributorByUserId(user_number,null);    IWorkItemWorkingCopyManager mgr = workitemClient.getWorkItemWorkingCopyManager();    IWorkItem workItem = fetchWorkItemById(teamRepo,projArea,'42');    mgr.connect(workItem, IWorkItem.FULL_PROFILE, null);    WorkItemWorkingCopy copy = mgr.getWorkingCopy(workItem);  			  IApprovals approvals = copy.getWorkItem().getApprovals();    final List<IApproval> approvalList = approvals.getContents();    final Iterator<IApproval> it = approvalList.iterator();    while (it.hasNext()) {    IApproval approval = it.next();    //This will fetch the current approver from the approval  final IContributorHandle currentApprover = approval.getApprover();    //Set new approver to the approval in case the current approver doesn't match the new approver    if (!newApprover.getItemId().equals(currentApprover.getItemId())) {    IApprovalDescriptor appDesc = approval.getDescriptor();    approvals.remove(approval);    IApproval newApproval = approvals.createApproval(appDesc, newApprover);    approvals.add(newApproval);    copy.save(null);      }  }  mgr.disconnect(workItem);  }  

Conclusion

We have seen how the user can create/customize approvals of work item both programmatically as well as through UI. Programmatic approach comes to play when there is a source system whose data need to be migrated to RTC. In such cases users can extract the required approvals information from their legacy system and then can create approval records in RTC. Similarly if there is a third party integration with RTC and both the system needs to have data synced, then any updation made on records in the third party can be replicated easily to RTC though vice-versa is currently not supported by RTC.

For more Information


About the author

Khayati Ohri is part of Rational Corp Tools team at IBM Software Labs, in India and working on RTC integrations with IBM legacy systems. Khayati holds a Bachelor’s degree in Information Technology and has eight years of experience in application development, primarily in Java technology. She can be contacted at khayatiohri@in.ibm.com.

Fri, 05 Oct 2012