Analyzing a Project Areas Members and Roles Using The Plain Java Client Libraries

I was interested in how to read the data from a Project and Team Area. This post shows my progress so far.

The purpose of the endeavor really is to be able to create a new project area from a certain template project area, copying over all information. I am not even nearly there yet. However Jian’s question on Jazz.net indicates that what I found so far might be interesting anyhow. 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 Jazz.net 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 API.

Download

You can download the code from here.

* Update *

The code to launch the methods is included in the download. It can also be found in several of the older posts, for example in Uploading Attachments to Work Items in the main() and the run() methods.

As a general statement, you should use the Java API to access the process information and not try to read the XML of the process directly. Please be aware that only the API documented in the Plain Java Client Library JavaDoc documentation is public API. You might end up using internal API and that is subject to change. Even for the public API there is no guarantee that it won’t change as far as I know.

You can access similar information by using the Generate Runtime Report on the project area’s context menu as shown below.

Generate Runtime Report*Update*

This code also works for

Finding a Project Area

The code provided either iterates over all project areas of a repository, or it finds the project area with a given name. Once it has located the project area, it calls the method analyzeProjectArea(teamRepository, projectArea) that takes care for the details.

The code needs some data. You can call it by providing the RepositoryURI, the user and password and optional a project area name like in the examples below.

Here the interesting code in the main method.

if (projectAreaName == null) {
	// For all project areas
	IProcessItemService itemService = (IProcessItemService) teamRepository
		.getClientLibrary(IProcessItemService.class);
	List pAreas = itemService.findAllProjectAreas(null, null);
	for (Iterator iterator = pAreas.iterator(); iterator.hasNext();) {
		IProjectArea projectArea = (IProjectArea) iterator.next();
		analyzeProjectArea(teamRepository, projectArea);
	}
} else {
	// For a specific project area
	IProcessClientService processClient = (IProcessClientService) teamRepository
		.getClientLibrary(IProcessClientService.class);

	URI uri = URI.create(projectAreaName.replaceAll(" ", "%20"));
	IProjectArea projectArea = (IProjectArea) processClient.findProcessArea(uri, null, null);
	if (projectArea == null) {
		System.out.println("Project area not found.");
		return false;
	}
	analyzeProjectArea(teamRepository, projectArea);
}

Analyzing The Project Area

The code below is called and prints the process area description and the contributors for the project area and then iterates the team area hierarchy doing the same.

/**
 * Analyze a project area
 *
 * @param teamRepository
 * @param projectArea
 * @throws TeamRepositoryException
 */
public static void analyzeProjectArea(ITeamRepository teamRepository,
		IProjectArea projectArea) throws TeamRepositoryException {
	printProcessAreaDescription(teamRepository, projectArea);
	dumpContributors(teamRepository, projectArea);
	List teamAreas = projectArea.getTeamAreas();
	for (Iterator iterator = teamAreas.iterator(); iterator.hasNext();) {
		ITeamAreaHandle handle = (ITeamAreaHandle) iterator.next();
		ITeamArea teamArea = (ITeamArea) teamRepository.itemManager()
			.fetchCompleteItem(handle, IItemManager.DEFAULT, null);

		printProcessAreaDescription(teamRepository, teamArea);
		dumpContributors(teamRepository, teamArea);
	}
}

Printing the Process Area Description

This method prints the process are description that is not accessible as a string but as content attached to the process area.

/**
 * Print the description of the process area
 *
 * @param teamRepository
 * @param pa
 * @throws TeamRepositoryException
 */
public static void printProcessAreaDescription(ITeamRepository teamRepository, IProcessArea pa)
		throws TeamRepositoryException {
	IDescription desc = pa.getDescription();
	IContent content = desc.getDetails();
	String description = "";
	if (content != null) {
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		teamRepository.contentManager().retrieveContent(content, stream, null);
		try {
			description = stream.toString(content.getCharacterEncoding());
		} catch (UnsupportedEncodingException exception) {
			description = stream.toString();
		}
	}
	String summary = desc.getSummary();
	System.out.println(summary + "\n\nDescription:\n" + description);
}

Printing the Administrators and Team Members of a Process Area

This operation prints the contributors associated to the process area. It separates the administrators and the team members.

/**
 * Iterate over the contributors of the process area and print them sorted
 * as admins and as team members
 *
 * @param teamRepository
 * @param processArea
 * @throws TeamRepositoryException
 */
private static void dumpContributors(ITeamRepository teamRepository,
		IProcessArea processArea) throws TeamRepositoryException {
	System.out.println("Process Area: " + processArea.getName());
	System.out.println("Administrators");
	dumpContributors(teamRepository, processArea, processArea.getAdministrators());
	System.out.println("Team Members");
	dumpContributors(teamRepository, processArea, processArea.getMembers());
}

It uses the following code to iterate a list of contributors and print the information.

/**
 * @param teamRepository
 * @param processArea
 * @param contributors
 * @throws TeamRepositoryException
 */
private static void dumpContributors(ITeamRepository teamRepository,
		IProcessArea processArea, IContributorHandle[] contributors)
		throws TeamRepositoryException {

	for (int i = 0; i < contributors.length; i++) {
		IContributorHandle handle = (IContributorHandle) contributors[i];
		dumpContributor(teamRepository, processArea, handle);
	}
}

This code finally does the printing of the details of the contributor.

/**
* Dump the details of the contributors
*
* @param teamRepository
* @param processArea
* @param handle
* @throws TeamRepositoryException
*/
private static void dumpContributor(ITeamRepository teamRepository,
		IProcessArea processArea, IContributorHandle handle)
		throws TeamRepositoryException {
	IContributor contributor = (IContributor) teamRepository.itemManager()
		.fetchCompleteItem(handle, IItemManager.DEFAULT, null);
	System.out.print(": " + contributor.getUserId() + "\t"
		+ contributor.getName() + "\t" + contributor.getEmailAddress()
		+ "\t");
	IProcessItemService processService = (IProcessItemService) teamRepository
		.getClientLibrary(IProcessItemService.class);
	IClientProcess process = processService.getClientProcess(processArea, null);
	IRole[] contributorRoles = process.getContributorRoles(contributor, processArea, null);
	for (int j = 0; j < contributorRoles.length; j++) {
		IRole role = (IRole) contributorRoles[j];
		System.out.print(role.getId() + " ");
	}
	System.out.println();
}

* Update *

I just realized that using IRole there is no way to access the role name. Sometimes along the way the interface probably needed to be made richer and to not break the older version, an additional interface IRole2 was introduced. This code provides with the additional information.

	for (int j = 0; j < contributorRoles.length; j++) {
		IRole role = (IRole) contributorRoles[j];
		IRole2 role2 = (IRole2) role;	
		System.out.print(role.getId() + "[" + role2.getRoleName() +" " + role2.getRoleLabel() + "] ");
	}

Get The Latest Data

The API caches Data. If you want to make sure that the data is refreshed, use IItemManager.REFRESH instead of IItemManager.DEFAULT in the code above.

Only Analyze the Process Areas of One User

This code, result of this question on jazz.net, shows how to get only the process areas a certain user is member of in a repository:

	IContributor user = teamRepository.loggedInContributor();
	// If having an ID for the user as string
	//IContributor user = teamRepository.contributorManager().fetchContributorByUserId(user)
	IProcessItemService processItemService = (IProcessItemService) teamRepository
			.getClientLibrary(IProcessItemService.class);

	List processAreasOfUser= processItemService.findProcessAreas(user, null, IProcessClientService.ALL_PROPERTIES , monitor);

Summary

Using the API as described above allows you to run automation against project areas. although this describes client API, the server API is similar enough and allows you to do similar things for example to extend this example to iterate the team hierarchy.

I hope that these code examples will help users out there that have a need for more automation.