Running The RTC 4.x Extensions Workshop With RTC 5.0.x


Since the new 5.0 version of Rational Team Concert and the CLM tools is out now, would the Rational Team Concert 4.x Extensions Workshop still work with this version?

The short answer is: Yes!

* Update * The error described below can be fixed. See the update in the description.

I just quickly tested if the Rational Team Concert 4.x Extensions Workshop works with the newest release 5.0 and I was able to successfully smoke test it. The same applies to newer versions of RTC.

To test if it still works, I performed Lab 1 completely. The new setup tool introduced recently ran like a charm and this was successful.

I then ran Lab 2 and finally Lab 5 with the complete code accepted. All labs worked as advertised. I would not expect any surprises in Lab 6 (except the normal issues when trying to deploy).

Observations

As there are some things that I notice that are different from the 4.x versions. I will summarize them here.

After setting up the SDK an error shows up in some of the project explorers. The error looks like below in the project explorer:

ExternalPluginError_1It seems to be an issue with the build path if one looks at the details:

ExternalPluginError_2I can’t remember having seen this in the past. Initially it only seems to come into the way when launching and does not seem to have any ill effects. Unfortunately it prevents refactoring operations.

To get around it, when launching, use this dialog to skip this issue:

ExternalPluginError_SkipIf you check the ‘Always launch without asking’ option, be a ware that this could be problematic if your own code has errors as well.

* Update *

To get rid of this error you can delete the folder resources in the SDK folder installs/rtc-sdk/plugins/com.ibm.team.log4j.ui_1.2.0.v20140307_1622 after extracting the SDK.

In the other labs, the only thing that seemed to be different is that the Eclipse password secure storage is getting more persistent. You should probably provide a password, to avoid having to deal with it every time.

Summary

So you can run the Rational Team Concert 4.x Extensions Workshop with the current Rational Team concert version 5.0 and it is likely it will run also with later versions.

As always, I hope the code above helps someone out there with extending RTC.

Creating CLM Links With Back Link Between Work Items


CLM Links, especially the back links can be tricky. I ran into some issues with CLM links when working with a partner recently. I wanted to share this learning and protect others from bad surprises.

*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 com.ibm.js.team.workitem.commandline.helper 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.

I thought I had CLM links under control as posted in Following CALM Links using the Java Client or Server API and related posts. I had to realize that this was not entirely true and I am still baffled, why I did not realize this during testing.

The issue is, that back links are not automatically created when linking a work item to another work item with a CALM link. I have not looked into back links when linking to other CLM objects. This post will describe how CLM links with related back link between work items can be created. There are some limitations for versions prior to 4.0.6 that restrict when you can actually do this as described below.

License

As always, 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. Remember that this code comes with the usual lack of promise or guarantee. Enjoy!

Just Starting With Extending RTC?

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.

Creating Back Links from a Newly Created Item – Version 4.0.6 and later

* Update * See example participant attached to Enhancement Request 288105 for how creating a link with back link to a newly created item works in the server API.

Creating Back Links – Limitations for Versions Prior to 4.0.6

There are currently limitations for versions prior to 4.0.6  on using the back link creation. The back link creation is done behind the scenes. It requires the work items to already exist. Trying to create the link with back links when creating a work item can lead into a deadlock situation, where the created work item is not yet saved and locked, so that the other operation will time out on the lock. This is, for example, the case in a work item save operation participant.

Enhancement Request 288105 was created to provide this capability and has been solved for 4.0.6.

I have tried to get around the deadlock in previous versions, by changing when what gets saved and when the link is created in which direction, however, to no avail.

Creating Back Links on Saving a Work Item

The RTC API provides additional parameters, that can be used to communicate information across save operations. This can be used in several ways. One example is to communicate between participants and other server extensions. This can, for example be used to detect that a save was initiated by a participant and to avoid to run the same participant being triggered by the subsequent save, to avoid recursion as described in RTC Update Parent Duration Estimation and Effort Participant.

This mechanism is also used to communicate the need to create a back link for CLM links. The API provides the constant IAdditionalSaveParameters.UPDATE_BACKLINKS in the interface com.ibm.team.workitem.common.internal.IAdditionalSaveParameters. Please be aware that this is an internal API with all that entails.

If you provide the additional parameter during a work item save operation, the back links are automatically created too.

You can add the additional parameter in several ways as the code below will show.

Creating Back Links – Client API Example

The example below shows client API code that can be used in Eclipse client extensions and in automation provided with the Plain Java Client Libraries.

The code below is based on the WorkItemOperation class that I usually use in client extensions to avoid having to deal with all the exception handling. The WorkItemOperation is a client API class, that can be extended with your own code and allows to create, modify, and save a work item. The code below adds a CLM (for examples Tracks) link between two existing work items.

The constructor passes the load profile to load the work item that gets modified by adding the outgoing link. It gets the endpoint for the link that is supposed to be created and the other work item passed and stores them in fields.

In the overwritten execute() method, the magic happens. First a URI for the work item is created. In this case I use an URI that is based on the ID of the work item. Another way to create URI’s is based on the work item UUID. I chose this version, because that is the version created when linking work items manually. The URI is used to create a location and to create a target endpoint from the passed endpoint descriptor and the Location’s Absolute URI.

The important step is to add the additional save parameter in the line

workingCopy.getAdditionalSaveParameters().add(IAdditionalSaveParameters.UPDATE_BACKLINKS);

This is only one valid way to do it. As you can see in the server code, you can also add it to the save statement if you are using other ways of saving. This should also work for the WokringCopyManager in the client API.

private static class LinkTrackingWorkItemOperation extends
		WorkItemOperation {

	private IWorkItem fOpposite; // The other work item o link to
	private IEndPointDescriptor fIEndPointDescriptor; // The endpoint to use

	public LinkTrackingWorkItemOperation(IEndPointDescriptor iEndPointDescriptor, IWorkItem opposite) {
		super("Linking Tracking Work Item", IWorkItem.FULL_PROFILE);
		fOpposite = opposite;
		fIEndPointDescriptor=iEndPointDescriptor;
	}

	@Override
	protected void execute(WorkItemWorkingCopy workingCopy,
			IProgressMonitor monitor) throws TeamRepositoryException {
		IWorkItemClient workItemClient = (IWorkItemClient) ((ITeamRepository)fOpposite.getOrigin())
				.getClientLibrary(IWorkItemClient.class);

		URI myURI = ItemURI.createWorkItemURI(workItemClient.getAuditableCommon(), fOpposite.getId());
		Location location = Location.location(myURI);
		IReference targetEndpoint = IReferenceFactory.INSTANCE.createReferenceFromURI(location.toAbsoluteUri());
		workingCopy.getAdditionalSaveParameters().add(IAdditionalSaveParameters.UPDATE_BACKLINKS);
		workingCopy.getReferences().add(fIEndPointDescriptor,
				targetEndpoint);
	}
}

The operation is called using the code below, assuming the work items have been found already.

LinkTrackingWorkItemOperation operation = new LinkTrackingWorkItemOperation(
		ILinkTypeRegistry.INSTANCE.getLinkType(
				WorkItemLinkTypes.TRACKS_WORK_ITEM)
				.getTargetEndPointDescriptor(), opposite);
operation.run(linkdest, monitor);

Creating Back Links – Server API Example

The server API looks very similar, except it is not wrapped into an operation as shown above. Instead of adding the save Parameter to the workingCopy, it is added to the work item save.

	IWorkItemReferences targetReferences = fWorkItemServer
		.resolveWorkItemReferences(currentItem, monitor);

	IEndPointDescriptor tracksEndpoint = ILinkTypeRegistry.INSTANCE
						.getLinkType(WorkItemLinkTypes.TRACKS_WORK_ITEM).getTargetEndPointDescriptor();
	URI myURI = ItemURI.createWorkItemURI(fWorkItemCommon.getAuditableCommon(), currentItem.getId());
	Location location = Location.location(myURI);
	IReference target = IReferenceFactory.INSTANCE.createReferenceFromURI(location.toAbsoluteUri());

	targetReferences.add(tracksEndpoint, target);
	Set additionalParams = new HashSet();
	additionalParams.add(IAdditionalSaveParameters.UPDATE_BACKLINKS);
	// Save the trigger work item with the links we created
	IStatus saveStatus = fWorkItemServer.saveWorkItem3(currentItem,
				currentReferences, null, additionalParams);

Please note, this only works if both work items already exist when the link is created.

Creating Link and Back Link to a New Item  –  Server API Example

See example participant attached to Enhancement Request 288105 for how back link creation works in the server API in case the back link is from a newly created work item.

Summary

This post explains how to create CLM links with back link. The code above is experimental. I have tested the client code. The server code is untested and copied together from different methods. There might be typos and other issues due to copying the code together from different places. I couldn’t test due to the deadlock mentioned above. But that the deadlock occurs hints the code would work.

As always, I hope the code is an inspiration and helps someone out there to save some time.

New Version and Now What? Experiences With SDK and Plain Java API across Tool Versions


There is a new version of RTC – what does that mean in the context of my automation Plain Java Client Libraries tools and my Extensions based on the SDK? This very valid question was recently asked on Jazz.net at least partially in this question.

I looked into it as far as I was able to and answered it briefly in the forum. I think it is worth adding a blog post as well.

Please be aware, as always, this is my personal experience and not a statement of IBM. Please also remember, as stated in the disclaimer, that this comes with the usual lack of promise or guarantee.

Just Starting With Extending RTC?

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.

Java APIs

As described in this post, RTC has at least the following Java APIs:

  1. Plain Java Client Libraries – for stand alone Java client applications
  2. The RTC client side SDK – for Eclipse client and other eclipse based extensions
  3. The RTC server side SDK – for server side extensions

It is somewhat important to distinguish between the different API’s because there are different dependencies on versions in extensions using the SDK and Plain Java Client Library based Java Tools.

Versions in Extension vs. in the Plain Java Client Libraries

A Plain Java Client Library tool just requires the classpath to include a version of the Plain Java Client Libraries. It just calls the classes available and does not check for any version information.

The Extensions plug-in manifest can specify dependencies to features, plug ins and other objects available in the SDK. These dependencies optionally can include a specification for the version number required by the extension. It is possible to specify no version, a minimal version, a range and a specific version of the dependent object to be required for an extension.

Plug In Version Dependencies
Plug In Version Dependencies

If you have a dependency specified this way and the dependency can not be satisfied by the available version, your plugin will not load.

Client vs. Server

It is also necessary to distinguish between client extensions and server extensions.

A client extension runs standalone or in a client and can potentially run in any version of the client. The libraries used – Plain Java Client Libraries or client SDK installed that come with the client – have a version.When the client connects to the server the first thing the server checks is, if the clients version is compatible.

The RTC Development Team attempts to provide N-1 compatibility from client to server. This means, the RTC Server should be compatible with clients with lower minor version numbers and 1 Major version number. This is handled in the server as mentioned above. Looking at RTC 4.x it should be possible to access the 4.x server with clients of smaller 4.x versions down to a 3.x client (N-1).

The server checks the clients version and rejects a connection if the versions are known to be incompatible. N+1 is not tested and rated as incompatible. So it is not possible to connect a RTC 4.0.3 Eclipse client with a RTC 4.0.1 server. The server won’t accept the connection as displayed below. Please note, this is also true for a Plain Java Client Library client.

4.0.3 Client Incompatible to 4.0.1 Server
4.0.3 Client Incompatible to 4.0.1 Server

Client/Server Compatibility Summary

Please see the Infocenter for the most current client/server compatibility data. The information is also provided in this TechNote.

Running Plain Java applications inherits the N-1 compatibility that is attempted, if it was achievable.

I ran a work item creation Plain Java Client Libraries app from within 3.0.1.1 against a RTC 4.0.3 server with no problem. Same with 4.0.3 clients against 5.0.x servers and 5.0.x clients against 6.0.x servers.

If the server version is more than 2 major versions ahead of the used Plain Java Client Libraries, the client will fail with a version incompatibility error. The same happens if the server version is smaller than the plain java client libraries. Provide a correct and compatible version of the Plain Java Client Libraries.

An RTC client SDK Extension based on the SDK  deployed in a client inherit the N-1 compatibility, if it was achieved.

If you have an extension in the client deployed (for example the RTC 3.0 Eclipse client), the client should be able to connect to servers with higher version numbers  as explained above. So the client extension should run – provided it does not depend on a server side extension that is not deployed in that server.

Extensions, Version Compatibility and Upgrade

What is missing is what happens to my extensions that have been created with earlier versions of the client or server SDK.

I have upgraded my extensions from 3.x to 4.x over the years. My experience so far is that it always was a smooth transition. I have seen very little changes in the API, some few deprecated classes. The only major changes I have seen are new API’s and in RTC 3.x permission aware read access. It is necessary to think about unavailable read access in RTC 3.x or higher. In RTC 2.0 there was no read access restrictions and you could always read any data. Make sure your RTC extension does not run in an environment that violates the assumptions made when it was created.

To upgrade, I usually set up a new development workspace (I am now working with 4.0.1 and looking into going to 4.0.3 see https://rsjazz.wordpress.com/2013/02/28/setting-up-rational-team-concert-for-api-development/ ). I usually load or import my extensions created with older SDK versions and make sure they do compile, debug or test them quickly. I would create the update site from this version and deploy it.

Avoiding Version Dependencies in Extensions

However, it is not always necessary to do this. If you make sure there is no version conflict in the required plug-in dependencies, a plug in created in an earlier version should run in a newer version, unless there are breaking API changes such as classes or packages renamed or made unavailable.

I just built the Build On State Change Participant from the RTC Extensions Workshop with 3.0.1.1 and deployed it in 4.0.3 client and server. It worked as expected in both the client as well as the server without rebuild. The dependencies in the Example don’t specify a version number they require and therefore the deployment is not rejected.

However, since there can be API changes in newer versions, it is a good practice to test your extensions with a newer SDK anyway.

Summary

RTC supports N-1 compatibility between clients and servers, but not N+1 compatibility. If you have client extension or Plain Java Client Libraries based automation, the versions used should be equal or less than the server versions used.

Eclipse Extensions based on the SDK can be made somewhat version independent as long as there are no API changes that break the interface contracts.

As always I hope this information is useful to others and helps them with deploying their RTC or CLM solution.

Understanding and Using the RTC Java Client API


A lot of users have expressed the need to better understand how to set up and develop against the Plain Java Client Libraries and the client API in general. This post continues my series of best practices around extending and goes deeper into the mysteries of the client API.

There was a nice Jazz.net article posted recently that is also a good source of information about the client API. However, there can never be enough examples, so I think this is useful. Also check the many links to other sources in the Interesting Links page.

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.

Additional RTC Work Item API Examples

See additional links at the end of the article.

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. The interesting code can be found in the com.ibm.js.team.workitem.commandline.helper 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.

Getting Started With Developing for the Plain Java Client Libraries

If you want to develop for the Plain Java Client Libraries, I would suggest to follow this post and set up your development environment with the SDK and the Plain Java Client Libraries. A complete guidance is in Learning To Fly: Getting Started with the RTC Java API’s and the linked resources.

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

Debugging Client Code and Finding Information about the API

It is absolutely critical that you have set up your development environment as described in Setting up Rational Team Concert for API Development. If you have not done that, you are severely limited in what you can see and do. You can not debug your code and therefore will be almost unable to do anything.

Prepare Your Project to Allow Debugging

As described in Setting up Rational Team Concert for API Development in the section Setting Up Your Workspace for Plain Java Development and Make the SDK Source Code Available for the Plain Java Clients Libraries, the Eclipse Plugin Development Environment together with the RTC SDK can help you with developing Plain Java Client Library and Client SDK code.

If you create a new project for new code, create a Plug-In Project as described and add the main plugins that contain the API you want to use. The following dependencies are a good starting point.

DependenciesThe version numbers will depend on your SDK. Keep in mind you really just use the plugin to make searching the API easier by tricking the PDE into believing you want to develop a plug in. Your code will later run as a plain Java class.

In addition to these plug-ins, make sure the PlainJavaApi is in the build path of the project. Add the library to the project. In the package explorer right click the project, select Build Path>Add Libraries… 


AddLibrary

In the wizard select User Library, click Next. Select PlainJavaApi and click Finish.

Select_PlainJava

Make sure the PlainJavaApi library is ordered as described in Setting up Rational Team Concert for API Development in the section Make the SDK Source Code Available for the Plain Java Clients Libraries.

OrderLibaries

Create a main class able to access the API and login

Then you create your main class, that provides the main() method to be called later.

You can just create a Java Class and let the wizard add the main() method for you. I usually use the same package structure I use to name my plugins. E.g com.ibm.js.team. and call my class according to its usage.

I usually start with code that I grabbed from the CreateWorkItem class presented in this Jazz.net wiki page. You can download the example code from the Wiki Page. A typical main() method in a standalone client API tool looks like this code.

public static void main(String[] args) {
    boolean result;
    TeamPlatform.startup();
    try {
        result = run(args);
    } catch (TeamRepositoryException x) {
        x.printStackTrace();
        result = false;
    } finally {
        TeamPlatform.shutdown();
    }
    if (!result)
       System.exit(1);
}

The code starts the TeamPlatforn and if that worked passes the parameters. I usually again use the example code mentioned above and call the run() method passing the arguments for processing. The run method usually starts like the code below:

private static boolean run(String[] args) throws TeamRepositoryException {
	if (args.length != 6) {
		System.out.println("Usage: CreateWorkItemApproval [repositoryURI] [userId] [password] [workItemID] [approverUserID] [approvalName]");
		System.out.println(" [approverUserID] for example 'bob' ");
		System.out.println(" [approvalName] for example 'Code Review' ");
		return false;
	}

	String repositoryURI = args[0];
	String userId = args[1];
	String password = args[2];
	String workItemID = args[3];
	String approverUserID = args[4];
	String approvalName = args[5];

The code gets the required information such as the repository URI, the user id and the password to log in from the arguments. Then it uses this information to log into the repository. Typical code for this looks like below.

	ITeamRepository teamRepository = TeamPlatform
		.getTeamRepositoryService().getTeamRepository(repositoryURI);
	teamRepository.registerLoginHandler(new LoginHandler(userId, password));
	teamRepository.login(monitor);

Once you have successfully logged into the repository, you need the API entry points to actually do something with objects accessible to the API.

The LoginHandler looks as follows:

private static class LoginHandler implements ILoginHandler, ILoginInfo {

	private String fUserId;
	private String fPassword;

	private LoginHandler(String userId, String password) {
		fUserId = userId;
		fPassword = password;
	}

	public String getUserId() {
		return fUserId;
	}

	public String getPassword() {
		return fPassword;
	}

	public ILoginInfo challenge(ITeamRepository repository) {
		return this;
	}
}

Getting Required Client Libraries

You need Client Libraries to access any interesting client API in RTC. In the client API you use the ITeamRepository.getClientLibrary() call to get the client libraries that you need. You can find some examples in the code below. Getting a Client Library uses singletons so the operation should be fast.

	IProcessClientService processClient = (IProcessClientService) teamRepository
			.getClientLibrary(IProcessClientService.class);
	IAuditableClient auditableClient = (IAuditableClient) teamRepository
			.getClientLibrary(IAuditableClient.class);
	IWorkItemClient workItemClient = (IWorkItemClient) teamRepository
			.getClientLibrary(IWorkItemClient.class);

Common API

There is some common API available that can be used in the client and the server. This API usually has “Common” in the name. Examples are IAuditableCommon, IWorkItemCommon, IProcessCommon and some other classes. The namespace or package name always contains “common” as well, for example com.ibm.team.process.common.IProjectArea. It is a good idea to look into these first, because code created with them can be reused on the server as well.

Finding Information About the API

The next question is probably, how do you know which Client Libraries are available and what they are for.

Lets look at what the ones above do first. If you have set up your development environment according to the previous post and got the order of the plugin dependencies and the Plain Java Api library right, you can simply position the mouse pointer over one of the interfaces and browse the information available like below.

BrowseDocumentation

Please note: if you don’t see information, documentation or code while you are following this, make sure that the dependency for the package is added to the plugin.xml as described above. If it is and you still don’t get the source, make sure that the Plug-in Dependencies are above the user Library for the Plain Java Client Libraries PlainJavaApi in the list on the Order and Export tab of the build path as described at the end of the Plain Java Client Libraries section of this post. There are some few classes, where even this might not work, but it is typically nothing you would be interested in seeing anyway.

You can focus on the hover to browse more or follow the links. If you are interested in the methods available on the class, you can just point your mouse pointer on the class or interface and open its Declaration as shown below. You can also open the declaration from the hover, if you point to a class, new actions become available at the window.

OpenDeclaration

You can open the Type Hierarchy and even more. If you are interested in how that class or interface is used by the clients, just  browse the references in the Workspace.

BrowseReferencesIf you do this, the PDE searches the SDK for where the class or interface is being used. This will take a moment, so be patient. You are rewarded with a search window that shows locations where whatever you search for is being used.

BrowseTheSearchHitsYou can use the up and down arrow to navigate. The Eclipse Editor will show you the file and the code around the places the class of interest is used.

Try that with the IWorkItemClient. Notice that it extends IWorkItemCommon and open the declaration of IWorkItemCommon. Search for references and browse some of the code. Locate the findWorkItemById() method in the declaration and double click on it. The code and documentation is opened in a Java editor. You can use the same technique to find references as you used before.

Often searching for all the references just provides too many hits. It is easy to narrow down your search. Just select the item of interest such as the findWorkItemById() method and click on the Search menu item in the Main Menu.

BetterSearchSelect the menu item Java…

JavaSearch

You can search for what you are interested in, methods, types, match locations. You can also type some text for example *License, if you are looking for a Type and search the SDK for it. This is interesting if you don’t know what is there, but think it is related to, in this example License management.

If you search for types the match location really comes into play. You can narrow down the search for what you are interested in. As an example mark the parameter type ItemProfile in the method above. Open the search window for Java Search for it (use copy/paste if you want and paste the text into the search field, if you like).

TypeArgumentSearch

Select the Type Arguments for example or anything you are interested to look for, hit OK and search. Now you have way less hits. This way you can find any information about the API that you are interested in.

Finding the Client Libraries

At this point you should be able to answer the question how you can find the available client libraries. Just click on the getClientLibrary() method of ITeamRepository and search for the references and you get many hits that you can easily browse. Build up a list and try to understand the name patterns.

You can also look into the Plain Java Client Libraries JavaDoc for the supported API. If you search the SDK, you will find a lot more client libraries – which you can use, even if they are not supported.

Getting at Data in the API

If you just start with the API, the next issue is how to get at data in the API and how to work with it. The data is not just there, you have to find it based on some criteria and get your hands on it.

Lets assume a simple example. You call your new automation Plain Java Client Library Class and provide the ID of a work item to modify somehow, in addition to the user ID, Password and whatever other information you need to pass it.

Now you need to find the work item based on the ID, which you get as string. The code below shows how that looks like:

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

int id = new Integer(idString).intValue();	
IWorkItem workItem = workItemClient.findWorkItemById(id, IWorkItem.FULL_PROFILE, monitor);

What does the code do? First it gets a client library of Type IWorkItemClient that provides a method to find work items by ID.  Then it converts the string with the ID into an integer that can be used to be passed to it. It then calls the find Method and provides additional parameters. Finally it gets the work item.

Different Client Libraries are responsible for different parts of the API. They typically provide methods to locate and find items in the API that are related to their domain. The trick is to find them. Well, consider the previous sections and search for them. You will quickly understand the patterns.

This is pretty typical and actually rather simple code to get at data in the API. It is simple because you often don’t get the real object, but a handle. We will talk about how to work with those handles later.

Item Profiles for Loading

Because the data is stored in a database, you need to use client libraries to retrieve the data. Since the data for things like work items can be of a considerable size and you often don’t need all the data, you provide an ItemProfile for the thing you are trying to load. The ItemProfile determines the properties you are interested in and that need to be retrieved from the persistency layer.

IWorkItem provides several ItemProfiles that determine, which properties are provided for the Item when loaded. IWorkItem.FULL_PROFILE loads everything. If you are only interested in the summary, you might want to limit that. IWorkItem.SMALL_PROFILE only loads the basic properties. You can use several of the provided item profiles. If you look up the code for the item profiles, you can create load profiles yourself.

The code below creates a new ItemProfile for a work item based on the small profile and requests to also load the “Planned For” attribute.

ItemProfile loadProfile = IWorkItem.SMALL_PROFILE.createExtension(
	Arrays.asList(new String[] { IWorkItem.TARGET_PROPERTY }));

IWorkItem also provides a list of definitions for the built in properties (attributes and other things) of a work item.

Not all items provide you with predefined ItemProfiles to load data as easy as workitems do. Sometimes you have to create your own item profile. Any IItem type has a static ITEM_TYPE defined in its interface. You can use that to create an Item Profile. The code below shows how to create an ItemProfile from a type.

ItemProfile.createFullProfile(IProjectArea.ITEM_TYPE)

Expressions and Queries to find WorkItems

You can use queries that are already available or use the API to create expressions to find work items by special criteria.

Progress Monitors

Some API operations are long operations. They require an IProgressMonitor that is used in the UI to show progress to the user (and to cancel operations). In some contexts you are provided with a monitor by the UI. In others like plain Java Client Libraries classes called from the command line you don’t have one. You can typically pass a null, but I find it cleaner to use org.eclipse.core.runtime.NullProgressMonitor instead.

	IProgressMonitor monitor = new NullProgressMonitor();

The Plain Java Client Libraries define a SysoutProgressMonitor you can also use. If you are smart, you hook up a logging library with your own implementation.

Resolving Item Handles

As mentioned above you don’t always get the item, but a handle of type IItemHandle to an item or even a list of handles. The code below is an example.

URI uri = URI.create(projectAreaName.replaceAll(" ", "%20"));
IProjectArea projectArea = (IProjectArea) processClient
	.findProcessArea(uri, null, monitor);
IContributorHandle[] contributors = projectArea.getMembers();

Now you have your handle you need to get at the data. Regardless of what IItemHandle you have retrieved, in the Client API you can typically get the IItemManager implementation from the ITeamRepository class. You can use the IItemManager to resolve or fetch an item. The code below shows an example.

ITeamArea teamArea = (ITeamArea) teamRepository.itemManager()
	.fetchCompleteItem(handle, IItemManager.REFRESH, monitor);

The client API uses caching to optimize speed. You have to tell the ItemManager if you want to resolve using the cached data (if available), or if you explicitly want to refresh the cache, because the item might be modified elsewhere.

IItemManager.DEFAULT and IItemManager.REFRESH are the flags provided that I usually use.

After fetching the Item, you can cast it to the Type you wanted to resolve.

Casting

Regardless whether you read a value or write a value, you usually can’t just use the value. You need to cast the object you get to something you can use. A String, an Int, an enumeration literal, or for more complex itens to an ItemHandle and resolve the handle to be able to access the data.

If you want to set a value, you have to make sure that the Object you pass conforms to the attribute type as well.

It is very typical that you get an object back and have to cast it to something you can use. It is easy enough to use the debugger to find out what the object really is, if in doubt. I usually use instanceof to be sure.

if (workItem.hasCustomAttribute(customString)){
	Object value = workItem.getValue(customString);
	if (value instanceof String) {
		String attributeValue = (String) value;
		// do something with the value
	}
}

ClassCast Exceptions

If your data does not conform to the value that is returned or expected, your code will throw a ClassCastException. Use the debugging capabilities to understand what the Object is that you get back.

Illegal Argument Exception

This usually happens similar to ClassCastException if you pass a wrong class or object to a method. You don’t get a ClassCastException because the code has some built in protection and does not try to blindly cast.

In every case I have seen so far, it was always my fault. Check what type the method wants and try to figure out how to get it. Prominent examples are just passing strings with iteration, timeline, project area, contributor and other objects names. This will not work. In most of the cases you have to use a service or client library to look up these objects by their name or ID or whatever and resolve the result to pass it along.

Get the TeamRepository from an Item

Sometimes you receive IItems and need to understand where they came from, or you just don’t have an ITeamRepository object and need it to do additional work. IItems in the client API provide you with the method getOrigin() that allows you to access the TeamRepository of the Item. The code below shows how that allows you to get at that information.

ITeamRepository repo = (ITeamRepository) teamArea.getOrigin();

Also see the next section how to get the team repository if you only have a UUID.

UUID’s

Internally items in the repository are represented with unique UUID’s. In some cases it is easy to get the UUID. E.g. you can get the UUID from the item handle.

UUID itemUuid = itemHandle.IItemHandle.getItemId();

It is easy to get the teamRepository from the UUID

ITeamRepository repo = TeamPlatform.getTeamRepositoryService().getTeamRepository(itemUuid);

It is also desirable to get the Item from it. The code below helps here:

IItemHandle handle = [itemtype].ITEM_TYPE.createItemHandle(UUID.valueOf(uuid_string), null);

Where [itemtype] is one of the existing IAuditable classes such as IWorkItem, IQueryDescriptor, IBuildResult and so forth. The uuid_string would be the string representing the UUID. Once the handle is retrieved it can be resolved as described above.

This can be done if the type is known. One example is in build automation, where you would have the ID of a build result as text. The example below shows how to get the handle from a string with the UUID.

IBuildResultHandle resultHandle = (IBuildResultHandle) IBuildResult.ITEM_TYPE
			.createItemHandle(UUID.valueOf(buildResultID), null);

You can find the code for the full example here: Automated Build Output Management Using the Plain Java Client Libraries.

Getting the API in an Eclipse Plugin

If you are extending the Eclipse based clients you might be logged in already. So you don’t want to have to login again, but use the user context available.

If you have an IItem for example from a ISelection, you can use getOrigin() as desccribed above to get the TeamRepository.

Otherwise you can just use the TeamPlatform to get an entry to get at data, because it should be available and you should be logged in. The code below shows an example.

	// Find the repositories
	ITeamRepository[] repos = TeamPlatform.getTeamRepositoryService().getTeamRepositories();
	for (ITeamRepository iTeamRepository : repos) {
		String user = iTeamRepository.getUserId();
		System.out.println("User: " + user);
	}

Creating and Modifying Items

Update: See the next topic about a better method for work items.

If you have an item, retrieved as described above, that does not mean you can actually modify it. So far you can only read its data and act upon it. If you want to modify data you might need to get a special object that allows you to modify the item. It is typically called a WorkingCopy. For work items for example, you need a WorkItemWorkingCopy. The code below shows how to get one and how to save the change.

IWorkItemWorkingCopyManager copyManager = workItemClient.getWorkItemWorkingCopyManager();

try {
	copyManager.connect(wi, IWorkItem.FULL_PROFILE, monitor);
	WorkItemWorkingCopy wc = copyManager.getWorkingCopy(wi);

	// TODO: Do something to the work item.

	status = wc.save(monitor);
	if (status.getCode() != org.eclipse.core.runtime.IStatus.OK) {
		return "Error: " + status.getDetails();
	}
} catch (Exception e) {
	return "Unexpected error: " + e.getMessage();
} finally {
	copyManager.disconnect(wi);
}

How do you know if you need a WorkingCopy? There does not seem to be a rule about this. It depends on the part of the API. Try it out, debug it and look for exceptions. If you run into the situation where you seem to be unable to modify the data you want, search the SDK for examples. There are different ways to create modify and save items, dependent on the type. You might have to search the SDK to find a method for the particular object you are dealing with.

Alternative to Create and Modify Work Items

I rarely use a WorkitemWorkingCopyManager these days, instead I wrap my changes to work items into a class implementing com.ibm.team.workitem.client.WorkItemOperation the WorkItemOperation as described in this Wiki page about programmatic work item creation and this and other posts on this blog. I found this the best way to create and modify work items in the client API.

You can use a WorkItemOperation for both creating and updating work items. You pass the parameters to the constructor and override the execute method. If you want to use the operation to update an existing work item make sure to provide an Item Profile in the super() call in the constructor.

The code below modifies a work item and adds an approval.

private static class WorkItemCreateApproval extends WorkItemOperation {

	private String fContributorUserID;
	private String fApprovalName;
	public WorkItemCreateApproval( String contributorUserID, String approvalName) {
		super("Create Approval",IWorkItem.FULL_PROFILE);
		fContributorUserID=contributorUserID;
		fApprovalName=approvalName;
	}

	@Override
	protected void execute(WorkItemWorkingCopy workingCopy,
			IProgressMonitor monitor) throws TeamRepositoryException {
		IWorkItem workItem = workingCopy.getWorkItem();
		// TODO: Do something with the work item here
		ITeamRepository repo = (ITeamRepository)workItem.getOrigin();
            // Find a contributor based on the ID
            IContributor aUser = repo.contributorManager()
                    .fetchContributorByUserId(fContributorUserID, null);
            // Find a contributor based on the login information
            IContributor loggedIn = repo.loggedInContributor();
            ArrayList reviewers = new ArrayList();
            reviewers.add(loggedIn);
            reviewers.add(aUser);

            // Create a new approval and add the approvers
            IApprovals approvals = workItem.getApprovals();
            IApprovalDescriptor descriptor = approvals.createDescriptor(
                    WorkItemApprovals.REVIEW_TYPE.getIdentifier(),
                    fApprovalName);
            for (IContributorHandle reviewer : reviewers) {
                IApproval approval = approvals.createApproval(descriptor,
                        reviewer);
                // Approve @See https://jazz.net/library/article/1118/
                approvals.add(approval);
	}
}

If you use a WorkItemOperation, you can later call the operation like in the code below:

WorkItemCreateApproval operation = new WorkItemCreateApproval(approverUserID, approvalName);
operation.run(workItem, monitor);

The code below creates a work item and sets some values and is basically grabbed from the Wiki page about programmatic work item creation.

private static class WorkItemInitialization extends WorkItemOperation {

	private String fSummary;
	private ICategoryHandle fCategory;

	public WorkItemInitialization(String summary, ICategoryHandle category) {
		super("Initializing Work Item");
		fSummary = summary;
		fCategory = category;
	}

	@Override
	protected void execute(WorkItemWorkingCopy workingCopy,
			IProgressMonitor monitor) throws TeamRepositoryException {
		IWorkItem workItem = workingCopy.getWorkItem();
		workItem.setHTMLSummary(XMLString.createFromPlainText(fSummary));
		workItem.setHTMLDescription(XMLString.createFromPlainText(fSummary));
		workItem.setCategory(fCategory);
			
		List tags = workItem.getTags2();
		tags.add("NewTag");
		workItem.setTags2(tags);
	}
}

The code gets called as shown below

WorkItemInitialization operation = new WorkItemInitialization(summary+" No: "+i, category);
IWorkItemHandle handle = operation.run(workItemType, monitor);

The difference between modifying and creating is in the call to the operation.

  • To modify the work item you pass the item or its handle
  • To create a work item you pass the type of the work item to be created

In both cases you can provide a load profile in the call to super(). If you modify the work item you must provide a load profile.

Working With Work Items Attributes

Please see Working with Work Item Attributes for more examples and how to find even more.

Accessing Work Item Attributes

If you use an Item Profile to load a work item, you typically intent to access its attributes. Please be aware that the work item itself has only very few methods to access the basic data of the work item. To access most of the attributes you need an IAttribute interface first. There are several ways to achieve that. You can look them up if you have the ID.

If you know the work item ID, it is possible to find the work item form the string value.

IWorkItemCommon workItemCommon = (IWorkItemCommon ) fTeamRepository.getClientLibrary(IWorkItemCommon.class);
IAttribute attribute = workItemCommon.findAttribute(projectArea, attributeID,
				getMonitor());
if(attribute != null){
	// Do something with it.
}

Or you can get a list of all the attributes that are built in.

List builtIn = workItemClient.findBuiltInAttributes(projectArea, monitor);

You can get the custom attributes from the work item itself.

List attribs = workitem.getCustomAttributes();

Please be aware it is a good idea to look for the ID’s if you look up attributes, if you do fuzzy matches by name, you might end up using the wrong attribute.

You can find the atribute ID in the Web Project Area Administration UI in work item types and attributes.

WebUI_AttribID2016-04-25_16-41-46

Once you have the IAttribute, you can use that to get the value from the work item. See Working with Work Item Attributes to get more information. You have to cast to the correct types to use the values and when you set values, you have to provide the right types too. Here in the Jazz.net Forum is a nice example that outputs all data of a work item provided as an answer by Sam.

Here one example:

if (workItem.hasCustomAttribute(customString)){
	Object value = workItem.getValue(customString);
	if (value instanceof String) {
		String attributeValue = (String) value;
		// do something with the value
	}
}

Enumerations and some other built in attribute types are a bit special. See the post about working with enumerations, the post about working with iterations and the post about working with work flow states and actions for more details.

WorkItem Data not Based on Attributes

Not all work item data is based on attributes. Most popular are subscriptions, attachments, approvals and Links.

Links between work items are special. See this post with some code that can be used to link work items and other elements. Also see the server link API post for some special cases you want to consider in the client too.

Stale Data Exceptions

I saved a work item and now I have a stale data exception. Why? Well, the reason for that is that someone changed the work item after you resolved it. It is always a good idea to resolve a work item short before you want to do an update. We will see this again in the server API.

ClassCast Exceptions

Regardless whether you read a value or write a value, you usually can’t just use that value. You need to cast the object you get to something you can use. A String, an Int, an enumeration literal, or for more complex itens to an IItemHandle and resolve the handle to be able to access the data.

If you want to set a value, you have to make sure that the Object you pass conforms to the parameter type as well.

If your data does not conform to the value that is returned or expected, your code will throw a ClassCastException.

ImmutableProperty Exceptions

As mentioned above, many objects can not just be changed. You need a WorkingCopy to do so. There are different ways how to get a working copy for different objects.

Null Pointer and Other Exceptions

I get exceptions, the API is broken!

My experience so far is, that it was usually my fault. I didn’t understand the API, failed to resolve another item or made wrong assumptions that led to exceptions. The best approach is to really look into all parameters you pass. Also check if the client libraries you intent to get using the getClientLibraries() really return. One example where you won’t get it that way is the is the IContributorManager, which you don’t get using this call, but using ITeamRepository.getContributorManager(). If you try to get the Client Library it will return null.

Permissions and Read Access

In the last releases more and more API is added to handle read restrictions to items. Make sure that you use the permission aware API like in this blog post or in this Jazz.net article. If you don’t you might have no access to data and even not recognize that this is the fact. See some permission aware API from the Defect178748Snippet.java that ships with the plain Java client libraries below.

private static void processSuspectWorkItems(ArrayList suspectWorkItems, boolean [] hasWarnings, ITeamRepository repo, IProgressMonitor monitor)
       throws TeamRepositoryException {
   IFetchResult result = repo.itemManager().fetchCompleteItemsPermissionAware(suspectWorkItems, IItemManager.DEFAULT, monitor);
   for (Object o : result.getRetrievedItems()) {
       IWorkItem wi = (IWorkItem)o;
       System.out.println("Found suspect workitem " + wi.getId() + ": " + wi.getHTMLSummary().getPlainText());
   }
   if (!result.getNotFoundItems().isEmpty()) {
       hasWarnings[0] = true;
   }
   if (!result.getPermissionDeniedItems().isEmpty()) {
       hasWarnings[1] = true;
   }
}

The permission aware API returns an IFetchResult that allows you to access enough data to decide if you didn’t have access to some items.

List retrieved = result.getRetrievedItems();
List permissionDenied = result.getPermissionDeniedItems();
List missingItems = result.getMissingItems();
List notFoundItems = result.getNotFoundItems();
// Do something with each list.

Operational Behavior, Permissions and Write Access

Please be aware that operational behavior permissions and write access also work in the client API. If you are not allowed to save a work item in a state, because there are required attributes, you will not be able to do so using the API either. So you have to take the permissions and other restrictions into consideration. Potentially you need to create a special role for an automation user, to override preconditions and give the correct permission.

Currently some modification that are only governed by presentations, for example work item editor presentations might be possible with the API and not throw errors. Don’t count on this not going to change.

Debugging and Calling your Code

I find it essential to run and debug the code I write often, especially if I don’t know the area of the API I am dealing with by heart. Since I don’t know any area by heart, I debug early and often 8-). You should do that too.

You should set a break-point into your code at the beginning of an interesting section.

There are some tricks, that can make it easier for you. If you use a main operation like above, you can create a debug configuration and store it in your project along with the client you are writing.

First create a folder called Launches in the project you are developing. This folder will contain your debug and run configurations. You can put it under SCM and share it with others.

Then go into the debugging perspective and open the Debug Configurations editor for example using the Run menu item.

The Debug Configurations editor should come up and allow you to create a configuration like below. Well, yours is probably empty at the beginning.

DebugConfigurationsAdd a new configuration. If you develop a stand alone command line client add a new launch for a Java Application. If you develop an Eclipse Client extension I would encourage you to start with a main method and a java Application Launch too, if at all possible. It saves you to create an Eclipse^2 launch and launching a debug Eclipse every time. You can wrap your code into an extension later. In any case the trick with saving the launch works for all launches.

First configure your project and main class.

Launch_1Next provide the arguments on the Arguments tab.

Launch_2Last step is to go to the Common tab. Select Shared file  and select your Launches folder to store the launch.

Launch_3

Push the Apply button and you saved the launch. Press the Debug button to start debugging.

You can find your Launch as file with the extension .launch in your launches folder. If you forgot to save it that way in the past, you can still change that later, by following the description for the Common tab.

The Launches will show up in the Debug Configuration section as soon as you have a project open with launches. so you can always manage and use your launches on different machines if they are available in their folder in a project. If you Use SCM you will automatically get them with the code for your project.

Run From Command Line

You can run from a command line as described in the README.TXT file you can find in the snippets folder in the Plain Java Client Libraries. What works for me is the command line call as follows:

rem Set JAVA_HOME="C:\IBM\ibm-jdk\"
%JAVA_HOME%/jre/bin/java -Djava.ext.dirs=%JAVA_HOME%/jre/lib/ext;C:/RTC403Dev/installs/PlainJavaAPI -cp ./bin/ com.ibm.js.team.workitem.automation.examples.ModifyWorkItemAddCommentOperation "https://clm.example.com:9443/ccm" "ralph" "ralph" "54" "Add a comment"

This is for Windows and assumes you have JAVA_HOME set and the Plain Java Client Libraries installed at the given location. It also assumes your source code is in a sub folder src/ and the binaries are located in a sub folder bin/ as they are in Eclipse projects. It also assumes the Java code is compiled. Please make sure there is a lib/ext folder available in the JRE.

If you create a jar file call as follows:

rem Set JAVA_HOME="C:\IBM\ibm-jdk\"
%JAVA_HOME%/jre/bin/java -Djava.ext.dirs=%JAVA_HOME%/jre/lib/ext;C:/RTC403Dev/installs/PlainJavaAPI -cp ./lib/;C:/RTC403Dev/installs/PlainJavaAPI -jar ModifyWorkItemAddCommentOperation.jar "https://clm.example.com:9443/ccm" "ralph" "ralph" "54" "Add a comment"

It is easy enough to modify this for Unix like operating systems by replacing ; by : in the -Djava.ext.dirs statement, fixing the usage of the environment variable and the paths.

Have a Test Repository

Did I mention, you should have a test repository to run your tests against? You should in any case test against some local test repository.

Download the Code

Some example code can be downloaded from DropBox. Please note, there might be restrictions to access DropBox and the code in your company or download location.

Related Posts

Performance

Please look at the post Boost Your Automation Performance Using an Automation Server for considerations if you run the automation a lot.

Summary

You should now be up and running for developing Eclipse Client or Plain Java Client Libraries standalone applications. You should know where and how to find the API and have the minimum set of information needed to get started without stalling on the second line of code. As always, I hope this post saves users out there some time – or is at least fun to read.

What API’s are Available for RTC and What Can You Extend?


This post is about what is available as API for RTC. I will try to provide you with some information about the available API’s. It was confusing to me in the beginning, so I assume others face the same problem.

This post assumes you already read the post about Setting up Rational Team Concert for API Development. Learning to Fly contains references to the most important posts for beginners. Please also consider to look into the Interesting Links page for more examples and downloads.You should understand the RTC Process Fundamentals if you want to do any extension or automation.

The post RTC Process Customization – What you can and cannot do is also a great resource to understand the basics.

The first API’s are only mentioned for completeness. They are not covered in this series of posts, but might be in the future.

REST and OSLC APIs

RTC provides some REST API’s that can be used to access and manipulate data. It also provides OSLC based APIs to access some of its data. See Consuming Rational Team Concert’s OSLC Change Management V2 Services to get started. See the Open Services for Lifecycle Collaboration Workshop and Using Perl to access the JAZZ REST API as an entry point. See Lyo OSLC 4J as a potential framework to access OSLC and REST APIs. This blog post provides you with a different browser extension to use for creating REST and OSLC URL’s.

JavaScript API

RTC provides a limited JavaScript API that can be used for Attribute Customization. The JavaScript API is very limited and allows only to access attribute data in the context of the work item the attribute customization runs. See this blog post or go directly to the Process Enactment Workshop for the Rational solution for Collaborative Lifecycle Management 2012 for some examples.

Relevant links

Available Java APIs

There are really two Java API’s available in RTC, and although they have much in common, there are differences that are important to understand if you want to use them. The following API’s are available

  • The Server API that is used in the server part of RTC (and JTS)
  • The Client API that is used by the Eclipse Client and the Plain Java Client Libraries

The server API is used by server extensions. Server extensions must extend com.ibm.team.repository.service.AbstractService. To get other services use com.ibm.team.repository.service.AbstractService.getService(Class) providing a server service class. Note, the server services used must be entered as prerequisite in the server extensions plugin.xml.

The client API is typically retrieved by using com.ibm.team.repository.client.ITeamRepository.getClientLibrary(Class) providing a client service class.

Please see the relevant examples for details.

RTC Server API

The RTC Server API is used in extensions to RTC that are deployed on the server. Examples for these kind of extensions are Operation Advisors, Operation Participants, Server Tasks and other extensions that are run on the server. The RTC Server API is shipped with the RTC SDK that you set up to have an environment for development. This API is typically found in packages called com.ibm.team.*.service and the interfaces are usually named *Service or *Server for example IWorkItemServer.

This blog has several examples for how to extend RTC using the server API. For example

RTC Common API

Parts of the API are available on the client and on the server. The way you get the API depends on if you have a client or a server extension, however, the services are available as client libraries as well as as services. This API is typically found in packages called com.ibm.team.*.common and the interfaces are usually named *Common for example IWorkItemCommon. In some cases the required services are provided by the extension mechanism. This allows to write some extensions that run on the server, as well as on the client. A good example are Attribute Customization providers. You can find examples in these posts

RTC Client API

The RTC Client API is used in Extensions to any of the Eclipse based RTC clients as well as in the RTC Plain Java Client Libraries. This API is typically found in packages called com.ibm.team.*.client and the interfaces are usually named *Client for example IWorkItemClient. The RTC Client API is shipped with the RTC SDK and partially shipped with the Plain Java Client Libraries.

What? The Client API is shipped twice? Why would anyone do that?

RTC Client SDK

The reason for shipping the client API in the RTC SDK and the Plain Java Client Libraries is really simple. You need it in the SDK to develop extensions for the Eclipse based RTC clients. The SDK provides you with the source code and allows to search the code in the Eclipse Plugin Development Environment PDE. Strictly speaking, you would not need the source code to develop the extensions, because the Eclipse client has the relevant parts of the API already installed as plug in’s and that is enough to be able to write extensions. However, it makes development so much easier. The RTC (client) SDK also ships some internal classes and tests that you can use to find examples for the API usage.

Plain Java Client Libraries

If you just want to run a small Java application to do some automation outside of the Eclipse client, you would need only the JAR files for the API, and some JAR files that it depends upon. It would be quite some effort to identify the JAR files in the Eclipse client you need. So the Plain Java Client Libraries  has the required JAR files bundled for you to use. This makes setting up a Plain Java Client application you developed much easier.

The Plain Java Client Libraries ship only the documented and public API. They are missing a lot of RTC Eclipse client specific code.

The post A RTC WorkItem Command Line Version 2 provides an extensive example for using the API to create and modify work items.

Extending Eclipse based Clients

When mentioning you can develop Extensions to the Eclipse based RTC Clients, that was no typo. The Jazz SCM Command Line as well as the Jazz Build Engine and Toolkit are also Eclipse based clients that can be extended. You can find an example for extending the Jazz Build  Toolkit in this post from Robin. The Eclipse Extension mechanism works for all Eclipse based clients.

There are several posts on this blog that talk about the client API. For Example

What is the Difference Between Client And Server API

Although you can often reuse the client API some things are different in the client and the server API so you need to be careful. The Services and Client Libraries have differences in how they are called and what they provide. Creating, getting and manipulating elements is sometimes slightly different in both API’s and you might need data on the server that you don’t have on the client and the other way round.

What can you Extend and Access?

The Server API allows to extend

  • The RTC Server with operational behavior, event handling, jobs and the like.

The Client API allows to extend

  • The Jazz  Build Engine and the Build System Toolkit
  • The SCM Command Line
  • The RTC Eclipse client
  • Potentially any other Eclipse based client

The Client API allows you to access

  • The RTC server and the data in its repository
  • Parts of the JTS server, for example the User and License management

What can’t you extend?

As far as I know you can not extend the Visual Studio Client, nor the Windows Shell, because both are not Eclipse based.

The available Extension Points and Operation ID’s are explained here.

Why is the API Designed the Way it is?

If you start working against the API, you will realize that, from a human perspective, sometimes things appear overly complicated. For example if you work with enumerations, you need to look up all the literals to find one that has the same Label value as your string you want to use to set it.

My personal view on this is, the API is a byproduct of what needed to be developed to design clients and servers. In the client for example, you will typically have views, that need to show more than one element. Or you have drop down boxes to select enumeration values. This just requires to get at all the data such as literals, project areas etc. needed to be displayed in that context. There is just no need to be able to provide a method that takes some string and looks up an item that has a display value that matches that string.

If you want it to be easier, you can always wrap pieces of code up to better fulfill your requirements and reuse that code.

Don’t Mix Client and Server API

You need to be really careful, to understand what client API is and what server API. Client API usually has client in the package name and you get the services with getClientLibrary() calls. Server code usually has server in the package name and you get services using gerService() from the AbstractService type you extend.

There are some packages with common in the package name, and contain common code that can be used on client and server. Still, you would get the common classes using getService() on the Server and the analogous Client Library with getClientLibrary() on the client.

If you mix the Client and the Server API in a server extension, you might find it works in Jetty – because that potentially has the client and the server part available in the SDK. But once you deploy the  extension on the server it will not load because it can’t find the required bundles. The same applies for client extensions.

The next post will go into the details of the client API.

Setting up Rational Team Concert for API Development


There seem to be still a lot of questions around how to develop against the RTC API. I will try to cover the best practices I developed over the years in some posts on this Blog over the next few months. I will try to cover at least the following topics over time:

This post will provide some guidance on how to set up your development environment for SDK and Plain Java development. But before we look into that, some information on the general challenges involved with doing this kind of development.

If you want to skip the valuable introduction that follows, skip to “Getting Started”.

Preface

“All hope abandon ye who enter here”

Well, it is not that bad, really. Developing automation and extensions can be loads of fun and a very rewarding task. However, I have learned the hard way, that it can also be very challenging and I would like to use this section to set, or correct, some expectations and make some general statements about the domain you are going to enter, should you decide to continue your quest.

The SDK and the Plain Java Client Libraries are an Eclipse Framework based Java API. To work against it, will require Java skills. That should not stop you from trying, if you are only a Java beginner, but you should be aware that you might have to dig into how to do certain things in Java, which will cost time.

Because RTC and Jazz is based on Eclipse, even on the server, you will be exposed to a lot of the Eclipse extensibility and programming model. A lot of advanced frameworks and APIs are used underneath the API you will use. These frameworks, EMF as an example, are very performant and versatile. On the other hand they are also using advanced programming patterns and models. Therefore they are often very abstract and it is sometimes hard to understand the relationships of objects.

Especially EMF is far more abstract as PoJo’s. EMF provides capabilities to generate code for domain models from abstract models such as UML. The input model allows to describe objects, their attributes and the relationship between these objects. The code generated is very efficient and clearly separates model and implementation. It uses generated interfaces to represent model objects and generated classes that represent the implementation of the objects. Using Interfaces allows implementing multiple interfaces and multiple inheritance. This makes it sometimes hard to understand the structure and the purpose of objects, how they relate and how to get from one to another. Knowledge about EMF is not required, but will help to deal with finding around in the API.

In addition to using EMF, Jazz/RTC also uses a database to store its information. This means you have to look up data using specific API. To increase performance it does also not always provide you with all the related data, but with handles that you have to resolve. One example is work item attributes. A work item needs to be found and resolved from a handle. It provides you with only very few methods to access its basic data such as its ID. If you want to access more attributes, you have to look up the attribute interface for the specific attribute ID first and then use the information found to access the value on the work item. This means you will have to find and understand a process with several steps to get at the data and the services needed to get it.

If you intent to create client or server extensions, you should have at least a basic understanding of the how Eclipse Extension Points and Extensions work. It is possible to to do this without any knowledge, but it is not easy. If you don’t have experience with Eclipse extensions, I would suggest to get a book about how that works and how to develop them. There are several on the market and they will make things easier for you over time. Eclipse extensions use a declarative approach as well as Java code. Without any background it is easy to get into a situation where things don’t work and the reason is just a mystery. This is especially true when working with the plug-in XML and during deployment of plug ins.

RTC covers a lot of ground. It supports managing Work Items, planning with them, provides SCM, Build and process enactment. The process component allows modeling projects, teams, timelines, roles and ties the other capabilities together. This means a lot of capabilities and a lot of API. Even if there are areas where there is no official API yet, like for planning.

If you get started, it will feel basically like being stuck in your village 1000 or more years ago, with no map and the task to explore and conquer the world. At least that is how it felt (and still feels) to me. So the best you can do in the beginning, is to look at your task and find some information on how to get started.

Other than 1000 years before, nowadays we have a pretty global village and ways to get at information that were not available even half a century ago. So you can search the internet for examples that have an overlap with what you are up to. You can ask in the Forum and build up your network. If you ask in the Forum make sure to tag your question with the tag extending. If you are lucky and find information, you will have to find the missing pieces and discover new areas. Sometimes you will have to cross seas or chasms to explore what lies beyond. Over time you will create yourself a map of the world that is more or less detailed and more or less accurate. It will most likely have white areas and places described with “Here be Dragons”. So prepare yourself for exploring new areas every time you want to do something different. Just be aware you probably haven’t been everywhere yet and you might not know the customs of the other areas. Exploration is hard and sometimes dangerous. Keep reminding you of this fact. Be prepared for a rough ride with great rewarding discoveries on the way.

If there would be a complete map of this world, I would be happy to share it. As it is, the best I can do is share what I, and others, have explored. I and your other fellow explorers would be really happy if you share information on areas you discovered to make it easier for the ones that follow in our steps. This blog provides you with examples and links to blogs of other explorers in this realm that are sharing pieces of the map discovered so far. I will try to maintain a link page with pieces of the map other explorers have found.

Getting Started

The natural starting point is how to set up your environment for development. Being able to set up a development environment for the RTC SDK and the Plain Java Client Libraries still seems to be a hurdle when starting developing against the RTC API. So lets have a look how that works. For the books, I always wanted to share this information, but there were always more pressing matters. My apologies.

Setting up the RTC SDK

Regardless if you want to develop client or server extensions or if you just want to work against the Plain Java Client Libraries, from my experience you should first set up a RTC SDK based development environment. As you will see later on, what you will gain is worth the investment.

Follow the Rational Team Concert Extensions Workshop Lab 1 (See the beginning of the post for newer versions) as described below, to perform this task. I don’t intent to rewrite the workshop. This section will only try to provide you with some more context and additional information that makes it easier to understand which steps are important and which have to be done (or can be left out) to set up the development environment.

If you intent to develop Eclipse extensions for the Eclipse Client or the RTC Server, you should run this RTC Extensions workshop at least once. It provides you with a step-by-step description you can follow. It also provides you with useful example code that touches some areas of the RTC API.

* Update * there was a major overhaul of the RTC Extensions Workshop. The text below has been updated to reflect the new workshop.

* Update * there are some problems with the SDK when Running The RTC 4.x Extensions Workshop With RTC 5.0.x. Check the post for how to solve them or use 4.x for development – the APIs are mostly unchanged.

* Update * See also Running the RTC Extensions Workshop With RTC 6.0

When can I skip doing the Extensions workshop?

As described below, there are cases where you may be able to skip all or part of the Extensions workshop in order to only setup the development environment. When can you skip doing the workshop and when should you do it?

If you want to develop extensions for the server, you can skip the workshop if

  • You have done the workshop already
  • You are a Jazz developer that develops with the server API every day
  • You are are a subject matter expert that has already successfully developed a bunch of custom follow up actions and successfully deployed them.

If you only want to code against the Plain Java Client Libraries you can also only do Lab 1 and skip the rest of the workshop.

In all other cases you should definitely take the time to do the RTC Extensions workshop.

Minimal Setup Steps to Setup Your Development Environment

If you only want to code against the Plain Java Client Libraries, or if you want to just set up the SDK, the part of the workshop you should perform is Lab 1. At least run through the sections 1.1 Download and Unzip the Required Files, 1.2 Setup for Development. If you just want to do Plain Java Client Libraries you can skip all the following labs. You can basically scroll down to the section Setting Up The Plain Java Client Libraries below.

If you want to setup only the SDK you don’t have to run 1.3 Setup the RTC Tomcat Server,  to setup the development RTC server and you don’t have to run the WorkshopSetup tool. You don’t have to connect the Eclipse client to the Tomcat RTC workshop server at https://localhost:9443/ccm/ if you skip 1.3, instead you would likely connect to your team’s SCM system to version your code.

When setting up the SDK 1.4 Complete Setup of Your RTC Eclipse Client is only necessary if you want to use the SDK to develop client and server extensions. In this case I strongly recommend to run all the labs. If you want to test the extensions on a Tomcat based server you have to at least  run 1.3_12 in 1.3 Setup the RTC Tomcat Server, to be able to connect to that server.

Please follow the advice in the workshop for setting up the Eclipse workspace and use a folder named /workspaces/Dev1/WS . A second workspace would be named /workspaces/Dev2/WS . This greatly simplifies workspace management later.

You should use different folders to develop for different Versions of RTC. I usually follow the pattern /RTCDev, where version is the version of the release. For example for 4.0.1 /RTC401Dev/ as root. see the image blow. It is a best practice to keep the file name short, especially on Windows, because that OS struggles with long path names you tend to get with Eclipse.

Development FoldersIf you want to develop client or server extensions, I strongly recommend to set up a test server based on Tomcat and Derby for deployment tests. I use the JKE Banking aka Money that Matters example for all my initial tests. If necessary, I deploy custom templates and create customized project areas on my test server. It is possible to backup the test server to be able to repeat deployment tests without always having to set up a new test server. With Tomcat and Derby you can zip the complete install folder for backup and unzip it to restore. This can be improved if you just backup and zip the data required. You can find some more details about what is required for backing up here.

As a general best practice, at least on Windows, use 7Zip to zip and unzip files related to Jazz and RTC. The zip tool built into Windows has problems with long path names and just does not work reliable. See the article Workaround: Rational Team Concert SDK .zip fails to extract on Windows because of long file path for details.

To run your own Tomcat test server for debugging, you have to modify the server.startup.bat file of this test server as described in the beginning of 1.3 Setup the Tomcat Server. If you do, run the rest of Lab 1 and make sure you can do the basic debugging steps as described in the last sections of the lab with your own test server.

If you run the test server on your development machine, make sure to avoid using conflicting ports as described in the RTC Extensions Workshop.

In my experience it is not necessary to run the workshop on the exact version you finally want to develop for. You can run the workshop on any supported version. Later you can set up the SDK for the version you want to use, as described here and bring the source code over. As an alternative, if there are issues with the versions (which should no longer be the case) you can set up the workshop on a supported version, upgrade the repository to the version you want and run it. Because the code did not change since 3.x, I don’t think it is worth the effort.

Running the Workshop – Additional Information

Please Note: If you run the workshop, make sure to follow it closely for the parts you are doing. This workshop has been run many times in classes. The experience is, it works really well if you pay attention to the details. This holds especially true for Lab 1. If you miss to check a check-box, or push the wrong button, or import the wrong file the wrong way with wrong selections, you will have issues. In a case like that, the only chance you have is to delete the wrong import, or whatever it was, and do the step again. The trouble is to understand the issue from the symptoms later, if you don’t have the experience. In this case you might have to start all over, delete what you did so far and repeat all steps.

You should be aware that the workshop uses two different RTC/CLM servers. The server you set up in 1.3 Set Up The RTC Tomcat Server https://localhost:9443/ccm/ as displayed below, is an external workshop SCM and Test repository simulating a production environment. It is used to get the source code of the workshop example. The code is stored in the repository in several states of development each marked by a baseline. In addition this workshop server is used as deployment target in the final lab.

ExtensionWorkshop Development RepositoryThe second server that you use in the workshop is the Jetty based Test Server you run in debug mode with the public URI https://localhost:7443/jazz/.

ExtensionWorkshop topologyJettyIt is a best practice to use a Jetty based test server to develop and test your code as described in the workshop, before attempting to deploy on a test system and finally in production. The reason is simple, it is much faster to develop this way. You can get your extension stable and you will be confident it works. In the final deployment tests on Tomcat or WAS you will likely only have to deal with deployment problems.

In a real production environment, you would connect to your development repository RTC server and use its SCM system to store your code. You would have your own test RTC server, as suggested above, that you use for your final deployment tests. This test server needs to be enabled for debugging, if you want to use remote debugging as mentioned above. In the workshop the Tomcat based RTC server is used for both purposes, like in a simulation.

Working With Your Development Workspace

If you followed the steps above, you have now a working Eclipse workspace as a development environment set up with the SDK. If you develop Extensions you can use this workspace to debug your extension, search for code in the SDK and do all kinds of cool things. Some of these capabilities are used in the Extensions Workshop. The key capability is, the SDK provides you with source code for many of the API classes which allows searching for the API.

It is a best practice to create a copy of your Eclipse workspace with the SDK set up and all its settings by just duplicating /workspaces/Dev1/ and naming the duplicate for example /workspaces/Dev2/. This duplicates all settings, including launches and jetty test servers. You can also use 7Zip to zip the folder /workspaces/Dev1/ and all its content as a backup.

You can also share the projects and files you imported into your workspace in the Jazz SCM. I would suggest to use a dedicated component. Please be aware that you still have to setup the SDK target platform and have to hook up the SDK source code if you start with a fresh workspace. Again, you can copy or zip/unzip your workspace that has been set up to sped up things and then load the component with the imported files.

Launches and Jetty Server Configuration

If you have run the Rational Team Concert Extensions Workshop and want to use the Feature Based Launches for a different RTC Version or Workspace, you can copy them over into the desired location. You can find these files in the Eclipse project RTC Extension Workshop Configuration.

Configuration and Launches

Use File>Import, select Existing Projects into Workspace. Then browse to the workspace that contains the project. Select the project to import and check the check box for the Copy projects into workspace option.

You can rename or remove launches for the client and the server and organize them as needed.

Make sure to remove the XML files in the conf folder and replace them with the ones for your current version.

Development, Debugging, Deployment of Server Extensions

You should use the techniques described in the Rational Team Concert Extensions Workshop to develop, debug and deploy your extensions.

Always use Jetty to test if server extensions solution can be deployed and work there first. After that is proven, you can be reasonably sure that it can be deployed on a real application server.

You can only be reasonably sure, because your extensions dependencies might still contain dependencies to code that is not available where you deploy it, or might experience problems with the class loaders of the application server.

However, your extension will then likely deploy and, in case there are unsatisfied dependencies or other issues, at least create an error message.

Use https://localhost:9443/ccm/admin?internal=true to see the internal tools that can help to request a server reset, see the provisioning status and the component status of your extension.

Internal ToolsYou can use

If you deploy and the deployment fails catastrophically, you can see this in the server logs e.g. as exception. If you fail to deploy correctly and, as an example, the ini file for the update site points to a non existent folder, you server might be unable to start and the links above won’t work.

Debugging Enterprise Extensions with Jetty

The Enterprise Extensions are not shipped with the SDK. If you need them for debugging in Jetty follow this answer on Jazz.net.

Setting Up The Plain Java Client Libraries

If you want to develop client extensions or Plain Java Client Library based automation it is recommended to set up the Eclipse workspace to use the Plain Java Client Libraries. You can use most of the code developed with Plain Java Client Libraries also for Eclipse client extensions and debugging of Plain Java Client Library code is faster and easier than debugging in a dedicated debug Eclipse client.

If you followed the Rational Team Concert Extensions Workshop Lab 1 you have already downloaded and installed the Plain Java Client Libraries.

If you haven’t, here is what is needed to download and extract them. Open the All Downloads tab of the RTC version you are interested in. For example https://jazz.net/downloads/rational-team-concert/releases/4.0.1?p=allDownloads and scroll down to the Plain .zip Files section. Look for the Plain Java Client Libraries downloads. There are the libraries as well as the JavaDoc.

PlainJavaDownloadDownload both files into a temporary folder.

Use 7Zip as explained in the workshop and unzip the Plain Java client Libraries download file (for example named RTC-Client-plainJavaLib-4.0.1.zip) using 7Zips Extract Files and provide the extraction Path /Installs/PlainJavaAPI .

ExtractLibrary

Now do the same with the JavaDoc for the Plain Java Client Libraries e.g. a file named RTC-Client-plainJavaLib-API-javadoc-4.0.1.zip. As extraction path provide /Installs/PlainJavaAPI/ as path again.

You should end up with this directory structure.

PlainJavaInstalled

Now you have installed the Plain Java Client Libraries. Familiarize yourself with the content of the folder PlainJavaApi. It contains the Jar files you need if you run Java code that uses the Plain Java Client Libraries. The doc folder contains the JavaDoc that you can open using the index.html file in that folder. The license folder contains the license files for it.

The snippets folder contains example code and a README.TXT file with instructions how to run the snippets. Basically you have to provide reasonable defaults for the parameters, compile the snippet code and run the snippets against a test repository. The snippets require the parameters repositoryAddress and snippetUserAndPassword. You can either set them as environment variables, or you can change the parameter default in the source code of the snippets displayed below.

SnippetParameters

You can edit the source with any editor, compile it with a JDK and run it from a shell. However, it is hard to debug this and it is impossible to search the API that way. Lets change that.

Setting Up Your Workspace for Plain Java Development

It would be great if we could run this in Eclipse and look for the API classes, similar to creating Eclipse extensions. The next sections show how that can be done, if you have setup your Eclipse with the SDK as described in the Extensions Workshop as described above.

Start your Eclipse client with the workspace set up for the SDK. You should see a few projects already that appeared during the setup for the SDK. Now we want the Plain Java snipptes to be usable in Eclipse for debugging.

Create a new Project using File>New>Project. In the wizard type Java in the filter or select Java>Java Project. Click Next. Name the Project PlainJavaSnippets and click Finish. Let Eclipse change to the Java Perspective. Now unfold the project, click on the src folder and create a new package. Name it snippets. Right click on the new package and select Import in the context menu. In the wizard select General>File System.

Click Next. Browse for /Installs/PlainJavaAPI/snippets. Select the folder snippets. In the Into Folder selection field, make sure it shows your package src/snippets in your PlainJavaSnippets project as presented below, then click Finish.

ImportSnippets

Now you have the code imported in your project and it shows errors, rats! But that is just because it is missing all the classes from the Plain Java client Libraries.

ImportedAndErrorsSo lets fix the errors first. right-click on the project and select Build Path>Configure Build Path.

AddPlainJava API LibrariesOpen the Libraries tab in the properties editor, then click Add Library. In the Add Library dialog select User Library and click Next. There is no User Library yet. Click on the button User Libraries… On the next dialog click New.

NewUserLibrary

Name the Library PlainJavaApi and click OK.

AddLibraryPlainJavaApi

On the next dialog click Add JARs… In the following dialog browse to /Installs/PlainJavaAPI/. Select all JAR files in the folder and click Open.

AddJARs

Your library should show a lot of JAR’s now. Click OK.

Jar's Added

On the next dialog make sure your new User Library PlainJavaApi is selected and press Finish. The Library should now show up in the build path. Click OK to close the Build Path Editor.

All the compiler errors should be gone after a moment. You can now run and debug your Plain Java Client Library snippets in Eclipse. Next time you want to create a new project, you can just re-use the library you have just created.

If you start new Plain Java Client Library based projects, just add this library to the build path and you should be ready to go.

Open Snippet1.java. and look into the main method. right click at TeamRepositoryException and select Open Declaration.

BrowseDeclaration

You will see a Class File Editor and, unless you installed a Java Decompiler, no code. Dang, we had hoped for more. And, we can actually achieve more, just using a little dirty trick described in the next section.

Make the SDK Source Code Available for the Plain Java Clients Libraries

This only works if you have installed the RTC SDK in your Eclipse following the Extensions Workshop. If you did not and just wanted to shortcut, this a bit, consider following the original advice.

The reason why we can see the code in plug-in development for the SDK is the Eclipse PDE – the Plugin Development Environment. Unfortunately that works only for plug-ins. We don’t have a Plugin – yet. We will have one in a minute and trick the PDE into showing us what we want.

Right click on the PlainJavaSnippets project and select Configure>Convert to Plug-in Projects…

ConvertToPlugin

In the wizard make sure your project is selected and click Finish.

Your project is now a plug in project. It will still not show any code. You have to tell it where to look first.

Unfold the new folder META-INF and double click at the file MANIFEST.MF.

AddDependenciesA plug in editor opens. Open the Dependencies tab of the editor and click Add…

AddDependencies2

In the Plugin Selection enter org.eclipse.core.runtime and add the dependency by pressing OK.

AddRuntime

The same way enter

  • com.ibm.team.repository.client
  • com.ibm.team.repository.common

Basically look into the import section of your snippet and add every dependency using the package name.

Dependencies

Save the changes to the plug in manifest.

Now we should have everything done to get the source code. However, the order of things to look up might cause an issue. Open the Configure Build Path dialog again as described above. Open the Order and Export tab and make sure the PlainJavaApi library is below the Plug-in Dependencies entry. Use the Up and Down button to achieve this, then click OK.

OrderLibaries

Now open your snippet again and use Open Declaration on TeamRepositoryExceptioen in the main method, as you did above. You should now be able to see the code that was imported in the SDK.This works, because the SDK and the Plain Java Client Libraries are basically the same code, but packaged in a different way.

This makes life a lot easier, because you can now use debugging and search and all other means available in the PDE to find the API you need. We will explore what we can do in future posts. See Understanding and Using the RTC Java Client API for more details on the client libraries.

Please Note: You can add more dependencies to the manifest, one for each package you need to look at. You should just make sure it is client API that is available in the Plain Java Client Libraries. You should be able to use Eclipse code completion with CTRL-Space for all the classes in the Plain Java Client Libraries. If you find a class and don’t see the code, try to add the package to the manifest. Please be aware that the SDK does not package the complete code. There are classes that don’t provide the source code.

It is a best practice to create a copy of your Eclipse workspace with the SDK and the Plain Java Client Libraries set up and all its settings by just duplicating /workspaces/Dev1/ and naming the duplicate for example /workspaces/Dev2/. This duplicates all settings, including launches and jetty test servers. You can also use 7Zip to zip the folder /workspaces/Dev1/ and all its content as a backup. This can save you a lot of time if you want to set up a fresh workspace later.

Summary

Setting up the SDK and development for the Plain Java Client Libraries helps you to explore and use the unknown lands of the RTC API and enables you to develop much more efficient than before. You should always invest the little effort to set up your environment this way.

I hope sharing this will help users out there to understand and develop the RTC API more efficient and provide more automation and extensions in less time.