Query Models or how to find stuff with the RTC Java API


Although I have done my share using and blogging about the API there are still a lot of uncharted areas. How can I use the RTC API to find a user by the name? This is a question that came up recently in the forum and is one of many questions, I did not have a good answer until today.

While writing my last post, for whatever reason I started thinking about this question. I decided to have a quick peek and try to find out. As a result this blog post describes how questions like that can be approached with the RTC Java API.

The Problem

The API provided for objects such as contributors, build results and a lot more model elements used in the RTC application is not necessarily the API a human would expect. This is because the API is written to make it easy to develop the tool and not to make it easy for a human to access data. So a question “How do I find a user by the name” is not necessarily something the RTC API would be optimized for.

If a user logs into RTC, they provide the ID and not the name. After login the user ID is available in the API and that is the glue used for almost all internal computation. The user name is usually nothing of interest to the API. However there are cases, for example integration scenarios, where questions like this might be of interest. So how does RTC solve this under the covers?

Work Item Queries

Please don’t confuse the Query Models in this post with work item queries and work item expressions. To search for work items see

License

The post contains published code, so 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. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, 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.

Compatibility

This code has been used with RTC 6.0 and is prepared to be used with RTC 6.0.x with no changes and it is pretty safe to assume, that the code will work with newer versions of RTC. It should however run with any version of RTC that has the specific API already implemented. The code shown below should work with almost all versions of RTC.

The post shows client, common and server API that are available in the RTC Server SDK and the RTC Plain Java Client Libraries.

Download

You can download the Eclipse project with the examples.  Please note, there might be restrictions to access Dropbox and therefore the code in your company or download location.

Solution

RTC works against a database. Some domains such as work items and SCM provide higher level query mechanisms to support user configurable queries in the UI to find stuff. Other domains do not.  But under the cover, the RTC API provides query mechanisms to query the database for data and to manage result sets.

The RTC API provides a common query service and  query models to be able to define and run queries for a wide variety of RTC objects.  The query service and the query models are common API and can be used in Java client applications, Eclipse client extensions as well as in RTC Server extensions.

Although there are questions and examples in the forums and there are some examples like this wiki page and somewhat hidden in this article (section Querying for Items), there is no good description how this works on a broader level. Needless to say that there is no description how to find the entry points into the API either. This post tries to help as good as possible.

How to find the query models

The best way to approach this is to setup a RTC Development environment by following the getting started post. Thsi means follow Setting up Rational Team Concert for API Development and the Extensions workshop and perform at least lab 1. Now you have an Eclipse with a RTC SDK set up that provides you with searchable example code. Without this environment, it is pretty pointless to try to approach this API.

You can use the naming conventions used while developing RTC to search for the query models. In the Plug-in Development Perspective select the menu Search>Java. Type *QueryModel as search string. Select declarations and the other choices shown below, then click Search.

searchquerymodel

Be patient while the SDK is searched. Dependent on the version of RTC you should finally see a search view similar to the one below.

searchquerymodelresult

Note that more than 960 query modes are found. There might be some duplicates and some might be totally uninteresting but there is obviously an enormous potential to access data in RTC.

If you know the model element interface you are interested in, for example an IBuildResult,you can use these approaches to find the related query model.

You can try to use the Eclipse content assist capability of the Plugin Development Environment (PDE) to find the related query model. Type in the name of the model element without the leading I and append QueryModel to it. To find the query model for IBuildResult, type BuildResultQueryModel. While you type use Ctrl+Space for content assist. The PDE should find the query model class.

contentassistpde

You can also use the search approach from earlier to search for the specific class BuildResultQueryModel with or without using the asterisk.

specificsearch

That way the Eclipse client, if set up correctly, allows to find the query model for the model element interfaces you are interested in.

What is provided by the query models?

The query models allow to define queries, to find model elements related to the query model. The query model provides comparisons, Boolean operations on properties specific to the model elements, sort and filter operations. The queries can be constructed and called with parameters. The queries can then be run using a query service and return a result set that can be further processed.

Example 1: Find the build results related to a specific build definition that are tagged with a specific tag.

Example 2: Find a Contributor by user name.

The entry point of a query model is the ROOT entry of the query model. It allows to instantiate queries against the query model and defines the interfaces available for the specific query model. These interfaces also specify which properties an object has, how to access them and the Boolean and other operations available to operate on this model element.

The image below shows the query model root BuildResultQueryModel.ROOT. It returns an implementation class. The BuildResultQueryModel interface also extends interfaces BaseBuildResultQueryModel and ISingleItemQueryModel.

querymodelroot

The interface BaseBuildResultQueryModel defines which properties the model element IBuildResult exposes in queries.

buildresultquerymodel

ISingleItemQueryModel defines operators such as equals or contained in providing a IPredicate interface.

isingleitemquerymodel

The IPredicate interface provides the interfaces to create the Boolean operations and, or, not.

ipredicate

Given this pattern, it is possible to create complex expressions.

Using the query models

Using the Query mechanism typically works in the following steps.
Create a query for the QueryModel for the model element (example [ModelElementName]=BuildResult.

IItemQuery query = IItemQuery.FACTORY.newInstance([ModelElementName]QueryModel.ROOT);

Create a predicate to filter the results based on some properties. This specific example uses a parameter of type string that gets a value passed. Instead of the paramter, it would also be possible to hard code a string here.

IPredicate predicate = [ModelElementName]QueryModel.ROOT.property()._eq(query.newStringArg());

Use the predicate from the step before as filter for the query.

IItemQuery filtered = (IItemQuery) query.filter(predicate);

Finally use the query service to run the query. Here a parameter of type string is passed to the query. Result sets can be big, so the last parameter is used to pass how many results should be retrieved.

IItemQueryPage page = queryService.queryItems(filtered, new Object[] { "Jerry Jazz"}, 1 );

All this can be as compact as in the following example.

IItemQueryPage page = queryService.queryItems(IItemQuery.FACTORY.newInstance(IterationPlanRecordQueryModel.ROOT), IQueryService.EMPTY_PARAMETERS, IQueryService.DATA_QUERY_MAX_PAGE_SIZE);

Get contributor by user name

Lets look at how the code for this forum question.: “How can I get the contributor for a user if I have the user name and not the ID?”. The code is inspired by very similar code that is used for the RTC Jabber integration.

We are looking for an IContributor. So the looking for the query model seems to be ContributorQueryModel.

First the code creates the query for the ContributorQueryModel. Then it creates a predicate to filter out a contributor with a specified name. The predicate uses an argument for the user name instead of providing the user name already here as string. The predicate is set as filter.

This is plain java client library code. There is no direct access to the com.ibm.team.repository.common.service.IQueryService. To get the IQueryService the code uses a trick. the IQueryService is available from the Implementation Class for ITeamRepository.  The teamRepository object is casted to com.ibm.team.repository.client.internal.TeamRepository. This makes the usage of QueryModels unsupported due to using unsupported internal code.

The IQueryService is indirectly available in some client libraries as well.

ITeamBuildClient buildClient = (ITeamBuildClient) teamRepository.getClientLibrary(ITeamBuildClient.class);
IItemQueryPage queryPage = buildClient.queryItems(query, parameters, IQueryService.ITEM_QUERY_MAX_PAGE_SIZE, monitor);

Once the QueryService is available the query is executed. In the example the user name is passed as a new parameter to the query. The result expects no more than one result.

The paged result is retrieved as list of handles and further processed.

// Create a query for the ContributorQueryModel
final IItemQuery query = IItemQuery.FACTORY.newInstance(ContributorQueryModel.ROOT);
// Create a predicate with a parameter to search for name property  
final IPredicate predicate = ContributorQueryModel.ROOT.name()._eq(query.newStringArg());
// Use the predicate as query filter 
final IItemQuery filtered = (IItemQuery) query.filter(predicate);
// Get the query service. This is a cast to an internal class. Note TeamRepository and not ITeamRepository is casted.
final IQueryService qs = ((TeamRepository) teamRepository).getQueryService();
// Run this ItemQuery. Note, there are also other types of queries qs.queryData(dataQuery, parameters, pageSize)
final IItemQueryPage page = qs.queryItems(filtered, new Object[] { findUserByName }, 1 /* IQueryService.DATA_QUERY_MAX_PAGE_SIZE */);
// Get the item handles if any
final List<?> handles = page.getItemHandles();
System.out.println("Hits: " + handles.size());
if (!handles.isEmpty()) {
	System.out.println("Found user.");
	// Resolve and print the information to the contributor object.
	final IContributorHandle handle = (IContributorHandle) handles.get(0);

Please note that there are various operations available to create the predicate and that the predicate can actually more complex. The code above uses the method

_eq()

to check for an equal string. In this case the match has to be exact.

Another option would be to search with ignore case option. This can be done using the following predicate definition:

final IPredicate predicate = ContributorQueryModel.ROOT.name()._ignoreCaseLike(query.newStringArg());

The complete code can be found below and is available for download. The downloadable code contains the example to search for the user by exact (case sensitive) user name and an example to search for the contributor by e-mai with a case insensitive match.

If the QueryUserByName example class is called with the required parameters like.

"https://clm.example.com:9443/ccm" "myadmin" "myadmin" "John Doe"

the result looks like this, provided the user exists, of course.

executionresult

Differences in the Server API

Server extensions must extend com.ibm.team.repository.service.AbstractService. This allows to use com.ibm.team.repository.service.AbstractService.getService(Class) to get the IQueryService in a server Extension like this:

IQueryService queryService = this.getService(IQueryService.class);

The rest of the API is as described above.

Dynamic Query  Model

There is also a dynamic query model based on the IItemType. It can be created as shown below.

IDynamicItemQueryModel dynamicQueryModel = IBuildResult.ITEM_TYPE.getQueryModel();

From the documentation in the code:

Generally, static query models should be used whenever they are visible and the types/properties are known at compile time. Note also that there are no API contracts regarding dynamic APIs – model objects may change shape, queryable properties, etc.”

So use the static version as described above.

Interesting examples in the SDK

Search for “Owned By” is in com.ibm.team.repository.client.tests.query.ExistsPredicateQueryTests.testExistsPredicateUsingLinks()

The full example code

Please find below the complete code for the RTC Plain Java Client Library version to find a contributor by its user name.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2017. All Rights Reserved. 
 *
 * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *******************************************************************************/
package com.ibm.team.workitem.ide.ui.example;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;

import com.ibm.team.repository.client.IItemManager;
import com.ibm.team.repository.client.ITeamRepository;
import com.ibm.team.repository.client.ITeamRepository.ILoginHandler;
import com.ibm.team.repository.client.ITeamRepository.ILoginHandler.ILoginInfo;
import com.ibm.team.repository.client.TeamPlatform;
import com.ibm.team.repository.client.internal.TeamRepository;
import com.ibm.team.repository.common.IContributor;
import com.ibm.team.repository.common.IContributorHandle;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.common.model.query.BaseContributorQueryModel.ContributorQueryModel;
import com.ibm.team.repository.common.query.IItemQuery;
import com.ibm.team.repository.common.query.IItemQueryPage;
import com.ibm.team.repository.common.query.ast.IPredicate;
import com.ibm.team.repository.common.service.IQueryService;

/**
 * Uses the ContributorQueryModel to search for a user by the user name 
 * and not the ID.
 * 
 * 
 * Example code, see
 * https://jazz.net/wiki/bin/view/Main/ProgrammaticWorkItemCreation.
 */
public class QueryUserByName {

	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;
		}
	}

	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);
	}

	private static boolean run(String[] args) throws TeamRepositoryException {

		if (args.length != 4) {
			System.out
					.println("Usage: QueryContributorByName [repositoryURI] [userId] [password] [NameOfUserToSearch]");
			return false;
		}

		IProgressMonitor monitor = new NullProgressMonitor();
		final String repositoryURI = args[0];
		final String userId = args[1];
		final String password = args[2];
		final String findUserByName = args[3];
		ITeamRepository teamRepository = TeamPlatform
				.getTeamRepositoryService().getTeamRepository(repositoryURI);
		teamRepository.registerLoginHandler(new LoginHandler(userId, password));
		teamRepository.login(monitor);

		/***
		 * There is a wide variety of query models available for several domains that allow to query 
		 * the elements and filter the results.
		 *
		 * For some examples on the topic
		 * @see https://jazz.net/wiki/bin/view/Main/QueryDevGuide#ExampleOne
		 * @see https://jazz.net/library/article/1229
		 */

		// Create a query for the ContributorQueryModel
		final IItemQuery query = IItemQuery.FACTORY.newInstance(ContributorQueryModel.ROOT);
		// Create a predicate with a parameter to search for name property  
		final IPredicate predicate = ContributorQueryModel.ROOT.name()._eq(query.newStringArg());
		// Use the predicate as query filter 
		final IItemQuery filtered = (IItemQuery) query.filter(predicate);
		// Get the query service. This is a cast to an internal class. Note TeamRepository and not ITeamRepository is casted.
		final IQueryService qs = ((TeamRepository) teamRepository).getQueryService();
		// Run this ItemQuery. Note, there are also other types of queries qs.queryData(dataQuery, parameters, pageSize)
		final IItemQueryPage page = qs.queryItems(filtered, new Object[] { findUserByName }, 1 /* IQueryService.DATA_QUERY_MAX_PAGE_SIZE */);
		// Get the item handles if any
		final List<?> handles = page.getItemHandles();
		System.out.println("Hits: " + handles.size());
		if (!handles.isEmpty()) {
			System.out.println("Found user.");
			// Resolve and print the information to the contributor object.
			final IContributorHandle handle = (IContributorHandle) handles.get(0);
			IContributor foundContributor = (IContributor) teamRepository.itemManager().fetchCompleteItem(handle, IItemManager.DEFAULT, monitor);
			System.out.println("UUID: " + foundContributor.getItemId());
			System.out.println("ID: " + foundContributor.getUserId());
			System.out.println("Name: " + foundContributor.getName());
			System.out.println("E-Mail: " + foundContributor.getEmailAddress());
			System.out.println("Archived: " + foundContributor.isArchived());
		}			
		teamRepository.logout();
		return true;
	}
}

Summary

As always I hope this helps someone out there with running RTC. Please keep in mind that this is as usual a collection of very basic examples with no or very limited testing and error handling. Please see the links in the getting started section for more examples, especially if you are just getting started with the RTC APIs.

Advertisements
Posted in Jazz, RTC, RTC Automation, RTC Extensibility | Tagged , , , , , , | 2 Comments

DIY stream naming convention advisors


Organizations might be interested in enforcing naming conventions for streams or make sure that stream names must be unique. This post shows some simple example advisor that check for a naming convention and make sure the stream name is unique.

License

The post contains published code, so 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. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, 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.

The example in this blog post shows RTC Server and Common API.

Compatibility

This code has been used with RTC 6.0 and is prepared to be used with RTC 6.0.x with no changes and it is pretty safe to assume, that the code will work with newer versions of RTC. It should run with any version that provides the operation ID.

The code in this post uses common and server libraries/services that are available in the RTC Server SDK.

Download

The code can be downloaded from here. Please note, there might be restrictions to access Dropbox and therefore the code in your company or download location.

Solution

Since some versions of RTC the operation ID com.ibm.team.scm.server.modifyStream has been made available. The operation allows to write RTC advisors (pre-conditions) and participants (follow up actions) that trigger on saving of a stream. The data that is made available in these operations allows to detect a variety of change types including a rename  of a stream.

RTC (version 6.x) ships the following out of the box preconditions for this operation ID:

  1. Ensure that snapshot names are unique for streams in the process area.
  2. Prevent Adding Component to Stream When Component and Stream Owners are Different.
  3. Prevent Adding User Owned Component
  4. Restrict Stream Visibility to be set to Public

The implementing classes are shipped with the SDK

  1. com.ibm.team.scm.service.internal.process.advisors.UniqueBaselineSetNameAdvisor
  2. com.ibm.team.scm.service.internal.process.advisors.StreamAddComponentAdvisor
  3. com.ibm.team.scm.service.internal.process.advisors.StreamAddUserOwnedComponentAdvisor
  4. com.ibm.team.scm.service.internal.process.advisors.StreamVisibilityAdvisor

Looking at the source code can be a great inspiration.

This post shows two advisors

  1. StreamNamingPatternAdvisor
  2. UniqueStreamNameAdvisor

StreamNamingPatternAdvisor checks for a simple naming convention and prevents creation or renaming of streams that violate the naming convention.

UniqueStreamNameAdvisor checks if the name of the stream is already used by another stream and prevents saving the stream if that is the case. Please note, the operation com.ibm.team.scm.server.modifyStream does not trigger if someone creates or saves a user repository workspace. This means it is not possible to provide this capability for  them.

General Approach

The operation ID provides a special interface IModifyStreamOperationData which makes the type of change and the related data available.

imodifystreamoperationdata

The code for the advisors first checks if the operation data provided is of the type IModifyStreamOperationData.If not, the operation terminates. If so, it casts to be able to use the interface to access the change details. If the data indicates anything other than a IModifyStreamOperationData.CHANGES, the advisor terminates.

IModifyStreamOperationData opData = (IModifyStreamOperationData) operationData;
if (!opData.isOperationType(IModifyStreamOperationData.CHANGES)) {
	// Nothing to do
	return;
}

If the operation is for such a change, the operation data can contain several different changes. So the code gets all the change ID’s for the changes in a set. The code then iterates the change ID’s and gets the change usinf the ID as IStreamChange. This interface allows to get more information, for example the identifier for the operation. In our case, if it is a name change IModifyStreamOperationData.NAME, the advisors are responsible to deal with it.

	// Get the set of change IDs and look through the changes
	Set changeIDs = opData.getChangeIds();
	for (String changeID : changeIDs) {
		IStreamChange change = opData.getChange(changeID);
		// Is this a stream name change?
		if (change.getIdentifier().equals(IModifyStreamOperationData.NAME)){
		........

The interface IStreamChange does not provide a whole lot of data to find out what actually happened. But the identifier gives a good idea. The IStreamChange is implemented by several interfaces that provide more information.

istreamchange

  • com.ibm.team.scm.common.process.IStreamComponentChanges is an interface to describe component changes on the stream
  • com.ibm.team.scm.common.process.IStreamFlowChange is an interface to describe flow target related changes on the stream
  • com.ibm.team.scm.common.process.IStreamPropertyChange is an interface to describe property changes such as a name change on the stream

The code can now cast to the specific interface IStreamPropertyChange and access the current and the new value of the property change. These values are the current name and the new name of the stream.

With the new name the code can run a basic validation. If the validation succeeds, the advisor terminates, otherwise it complains and fails the advisor.

The code below shows the whole advisor implementation. In this example the code looks for a very simple prefix ‘TEST_’ on the stream name. If the prefix is available it succeeds, it fails otherwise. This validation can be replaced by a more complex and potentially configurable method.

/*******************************************************************************

 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2017. All Rights Reserved. 
 *
 * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *******************************************************************************/
package com.ibm.js.scm.naming.advisor.service;

import java.util.Set;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.process.common.IProcessConfigurationElement;
import com.ibm.team.process.common.advice.AdvisableOperation;
import com.ibm.team.process.common.advice.IAdvisorInfo;
import com.ibm.team.process.common.advice.IAdvisorInfoCollector;
import com.ibm.team.process.common.advice.runtime.IOperationAdvisor;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.scm.common.process.IModifyStreamOperationData;
import com.ibm.team.scm.common.process.IStreamChange;
import com.ibm.team.scm.common.process.IStreamPropertyChange;
import com.ibm.team.scm.service.internal.AbstractScmService;

@SuppressWarnings("restriction")
/**
 * This advisor tests the name of a stream against a naming convention pattern.
 * If the stream name does not match the pattern, the stream can not be saved.
 * 
 * Note that this extension point does not get any change events for repository workspaces. It only works for streams.
 * 
 * 
 * There are several examples for extensions that are shipped with the product that can be looked into in the SDK.
 * @see com.ibm.team.scm.service.internal.process.advisors.UniqueBaselineSetNameAdvisor
 * @see com.ibm.team.scm.service.internal.process.advisors.StreamVisibilityAdvisor
 * @see com.ibm.team.scm.service.internal.process.advisors.StreamAddComponentAdvisor
 * @see com.ibm.team.scm.service.internal.process.advisors.StreamAddUserOwnedComponentAdvisor
 *
 */
public class StreamNamingPatternAdvisor extends AbstractScmService implements
		IOperationAdvisor {

	public static final String REQUIRED_PREFIX = "TEST_";
	public static final String STREAM_NAMING_ADVISOR = "com.ibm.js.scm.naming.advisor.service.streamNaming";

	@Override
	public void run(AdvisableOperation operation,
			IProcessConfigurationElement advisorConfiguration,
			IAdvisorInfoCollector collector, IProgressMonitor monitor)
			throws TeamRepositoryException {
		Object operationData = operation.getOperationData();
		if (!(operationData instanceof IModifyStreamOperationData)) {
			// There are some stream modify operations that are not process
			// enabled so they do not provide any data.
			return;
		}
		// com.ibm.team.scm.server.modifyStream is only called for streams.
		// Saving a repository workspace (which is really like a stream) does
		// not trigger the extension point.
		// This especially implies that it is not possible to test for unique
		// names across streams and workspaces. It is possible to
		IModifyStreamOperationData opData = (IModifyStreamOperationData) operationData;
		if (!opData.isOperationType(IModifyStreamOperationData.CHANGES)) {
			// Nothing to do
			return;
		}

		// Get the set of change IDs and look through the changes
		Set changeIDs = opData.getChangeIds();
		for (String changeID : changeIDs) {
			IStreamChange change = opData.getChange(changeID);
			// Is this a stream name change?
			if (change.getIdentifier().equals(IModifyStreamOperationData.NAME)) {
				/***
				 * Get the change details based on the change we identified
				 * 
				 * The supported types of changes for this extension point are
				 * 
				 * @see com.ibm.team.scm.common.process.IStreamPropertyChange
				 * @see com.ibm.team.scm.common.process.IStreamComponentChanges
				 * @see com.ibm.team.scm.common.process.IStreamFlowChange
				 * 
				 *      A name change is stored as IStreamPropertyChange
				 */
				if (change instanceof IStreamPropertyChange) {
					IStreamPropertyChange streamPropertyChange = (IStreamPropertyChange) change;
					String newName = streamPropertyChange.getNewValue()
							.toString();
					if (validateName(newName)) {
						// We are fine
						return;
					}
					String description = "The stream name violates the naming conventions stream name must have prefix '"
							+ REQUIRED_PREFIX + "'!";
					String summary = description;
					IAdvisorInfo info = collector.createProblemInfo(summary,
							description, STREAM_NAMING_ADVISOR);//$NON-NLS-1$
					collector.addInfo(info);
				}
			}
		}
	}

	/**
	 * Validate the name against the convention
	 * 
	 * @param name
	 * @return
	 */
	private boolean validateName(String name) {
		// Implement your own naming convention here
		if (name.startsWith(REQUIRED_PREFIX)) {
			return true;
		}
		return false;
	}
}

The UniqueStreamNameAdvisor only replaces the validation with a more complex one querying the SCM system for streams with a given name.

The code creates workspace search criteria to search for a stream, that happens to have the same name as the new name for this stream will be. If so, it fails. The search is limited to streams, because it is not possible to do this check for repository workspaces and a conflict would be hard to handle.

/**
 * Validate the name against the convention a stream must have a unique name
 * 
 * @param name
 * @return
 * @throws TeamRepositoryException
 */
private boolean validateName(String name) throws TeamRepositoryException {
	// Get the query service and set criteria
	IScmQueryService queryService = getService(IScmQueryService.class);
	final IWorkspaceSearchCriteria criteria = IWorkspaceSearchCriteria.FACTORY
			.newInstance();
	criteria.setExactName(name); // Look for the same name
	// Only for streams, we can not prevent creation of workspaces with the
	// same name either and a user could create a workspace with the same
	// name and prevent us from saving the stream later.
	criteria.setKind(IWorkspaceSearchCriteria.STREAMS);
	// We only have to find one other
	ItemQueryResult result = queryService.findWorkspaces(criteria, 1, null);
	if (!result.getItemHandles().isEmpty()) {
		return false;
	}
	return true;
}

Consolidation

It is relatively obvious and straight forward to consider refactoring the solution shown here. Create an abstract class that contains all the shared code of both classes, with an abstract method validateName(). Create implementations providing the implementation for the method validateName() and provide these implementation classes in the plugin.xml. That way it is simple to provide new versions for various naming conventions.

Code Structure

The code structure follows the general approach that has been used in this blog for quite some time now. The code comes in the following Eclipse projects used for the purpose explained below.

com.ibm.js.scm.naming.advisor.common is the project that defines the jazz component to be used by this extension. It is in a separate project to allow to use it in case of implementing an aspect editor.

com.ibm.js.scm.naming.advisor.launches is a project that contains the launches that can be used to debug the extension with Jetty.

com.ibm.js.scm.naming.advisor.service is the project that contains the server side extension code.

com.ibm.js.scm.naming.advisor.service.feature defines is the feature for the server side deployment of the extension.

com.ibm.js.scm.naming.advisor.service.updatesite contains the update site to build the server side extension.

com.ibm.js.scm.naming.advisor.service.serverdeploy contains the provision profile as well as the folder structure needed for the final deployment. To prepare deployment Build the update site and copy the plugins and feature folder into the  js_scm_naming_advisor folder. To deploy copy the provision_profiles and the sites folder with all their contents into the server/conf/ccm folder of the RTC server.

codestructure

Configuring the precondition

When running the custom advisor in Jetty or finally deployed the advisor can be configured as usual.

configuring

If configured, the advisors prevent saving streams that do not conform to the specific naming condition. The advisor displays the problem like below.

fail_unique_name

Summary

As always I hope this helps someone out there with running RTC. Please keep in mind that this is as usual a very basic example with no or very limited testing and error handling. Please see the links in the getting started section for more examples, especially if you are just getting started.

Posted in Jazz, RTC, RTC Automation, RTC Extensibility, RTC Process Customization | Tagged , , , , , | Leave a comment

A component naming convention advisor


Organizations sometimes would like to implement naming conventions for components based on the architecture for example. This post shows a simple example advisor that checks for a naming convention.

License

The post contains published code, so 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. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, 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.

Compatibility

This code has been used with RTC 6.0 and is prepared to be used with RTC 6.0.x with no changes and it is pretty safe to assume, that the code will work with newer versions of RTC. It should run with any version that provides the operation ID.

The code in this post uses common and server libraries/services that are available in the RTC Server SDK.

Download

The code is included in the download in the post DIY stream naming convention advisors.

Solution

In the last few versions of RTC several operations have been made available for operational behavior. At least since RTC 5.0.2 the operation to modify a component is available with the operation ID com.ibm.team.scm.server.component. This allows to create advisors/preconditions as well as participants/follow up actions that operate on such events. An example shipped with the product is implemented in the class com.ibm.team.scm.service.UniqueComponentNameAdvisor.

There are examples shipped with the product in the SDK that you can look at for more sample code. For example: com.ibm.team.scm.service.internal.process.advisors.UniqueComponentNameAdvisor

The code below shows a very basic example how to test the component name for some simple naming schema.

The important information to take away is that the information about the save operation is provided in a special interface IComponentModificationData which allows access to the type of the operation, to old and new properties and to the component directly.

componentmodification

So it is possible to find out what operation is done on the component and based on that look at the properties that the component has.

The code below does exactly that. It checks what operation is going on and then takes the new name of the component and checks it.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2017. All Rights Reserved. 
 *
 * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *******************************************************************************/
package com.ibm.js.scm.naming.advisor.service;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.process.common.IProcessConfigurationElement;
import com.ibm.team.process.common.advice.AdvisableOperation;
import com.ibm.team.process.common.advice.IAdvisorInfo;
import com.ibm.team.process.common.advice.IAdvisorInfoCollector;
import com.ibm.team.process.common.advice.runtime.IOperationAdvisor;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.scm.service.internal.AbstractScmService;
import com.ibm.team.scm.service.internal.process.IComponentModificationData;
import com.ibm.team.scm.service.internal.process.IComponentModificationData.OpType;

/**
 * An example advisor that checks the name of a component for some naming convention
 *
 * Also @see com.ibm.team.scm.service.UniqueComponentNameAdvisor for product example code
 */
@SuppressWarnings("restriction")
public class ComponentNamingAdvisor extends AbstractScmService implements
		IOperationAdvisor {
	public static final String REQUIRED_PREFIX = "TEST_";
	public static final String COMPONENT_NAMING_ADVISOR = "com.ibm.js.scm.naming.advisor.service.componentNaming";

	@Override
	public void run(AdvisableOperation operation,
			IProcessConfigurationElement advisorConfiguration,
			IAdvisorInfoCollector collector, IProgressMonitor monitor)
			throws TeamRepositoryException {

		IComponentModificationData data = (IComponentModificationData) operation
				.getOperationData();
		if (data == null) {
			throw new TeamRepositoryException("Missing component data"); //$NON-NLS-1$
		}

		String compName;

		if (data.getOpType() == OpType.CREATE) {
			compName = data.getNewName();
		} else if (data.getOpType() == OpType.RENAME) {
			compName = data.getNewName();
		} else {
			return;
		}
		if (validateName(compName)) {
			// Nothing to do
			return;
		}
		String description = "The component name violates the naming conventions component name must have prefix '"
				+ REQUIRED_PREFIX + "'!";
		String summary = description;
		IAdvisorInfo info = collector.createProblemInfo(summary, description,
				COMPONENT_NAMING_ADVISOR);//$NON-NLS-1$
		collector.addInfo(info);
	}

	/**
	 * Validate the name against the convention
	 * 
	 * @param compName
	 * @return
	 */
	private boolean validateName(String compName) {
		// Implement your own naming convention here
		if (compName.startsWith(REQUIRED_PREFIX)) {
			return true;
		}
		return false;
	}
}

Summary

This is as usual a very basic example with no or very limited testing and error handling. See the links in the getting started section for more examples. As always I hope this helps someone out there with running RTC.

Posted in Jazz, RTC, RTC Automation, RTC Extensibility, RTC Process Customization | Tagged , , , , , | 12 Comments

The RTC SDK is about to change in 6.0.3


Since some time now, the RTC and Jazz Development teams are in discussion how to cope with the version compatibility requirements driven by Eclipse clients and the server API. In RTC 6.0.3 the SDK is about to be split into separate SDK’s for the Eclipse client and the Server. This will impact how the development environment needs to be set up and how extensions are developed. I will try to share a summary of what to expect here. I have so far only been able to experiment with development builds, there has not been an official release of the SDK for 6.0.3 yet.

Download the new workshop

Update * the new Extensions Workshop is finished for a while now. Unfortunately I can’t get the update published at the original Rational Team Concert Extensions Workshop location due to site maintenance at the moment.

Therefore I decided to publish the latest version here in this blog for the time being. Please find the newest version compatible with RTC 6.0.3 and higher for download in the links below:

Why splitting the SDK?

The RTC Clients have been based on Eclipse 3.6 for a considerable amount of time now. This has been the case for the Jazz Servers as well. However, there is pressure on the server infrastructure for the need to support Eclipse 4.4.x and higher. On the other hand there are client applications that RTC needs to integrate with, that are lagging behind in adoption of new Eclipse versions.

As described in What API’s are Available for RTC and What Can You Extend? the RTC SDK currently contains the RTC Server API, the RTC Common API and the RTC Client API in one delivery. The RTC Common API is part of the RTC Server API as well as the RTC Client API. This is a potential problem when shipping the SDK and trying to keep the Server compatible to Eclipse 4.4.2 and above and being compatible with Eclipse 3.6 clients. As it looks, the RTC SDK will be split into two parts.

  1. A RTC Server SDK bundling the RTC Server API and the RTC Common API compatible with Eclipse 4.4.x and higher
  2. A RTC Client SDK bundling the RTC Client API and the RTC Common API compatible with Eclipse 3.6.x and higher

Impact of splitting the SDK

The split has various impacts on how extension development will now work. Please find below a short summary of changes that I have found necessary to perform the workshop.

Changes to section: 1.1 Download and Unzip the Required Files from jazz.net

The Server SDK Target Platform now requires an Eclipse 4.4.2 or higher. You can download the base Eclipse 4.4.2 client here. For example download the version Eclipse IDE for Java EE Developers. Install the client similar to described in the workshop. Then download the RTC Eclipse Client p2 install package and install this into your Eclipse 4.4.2.

In the Feature Based Launches download the new launcher442.zip. Unzip the zip file, browse to the enclosed JAR file and copy that into the dropins folder in the Eclipse client.

You might want to consider to do the following changes to the eclipse.ini file.

  • Add a section -vm with an additional line for the java virtual machine to use. If you run Eclipse with a different JVM, e.g. from Oracle, consider to specify a JRE or JDK that is compatible with the one that ships with RTC. This vm would also be used in the workspace setup section.
  • Add -showLocation in the org.eclipse.platform section; this shows the Eclipse workspace path in the upper border of the Eclipse client as below
    eclipse-workspace_2016-11-07_11-23-52
    This makes it possible to actually work with multiple workspaces and knowing which an Eclipse instance is responsible for.
  • A vmargs argument -Duser.language=en to make sure you get a consistent language in the menus if you want.

The image below shows the changes in my caseeclipse-ini-2016-11-07_11-09-02

Changes to section: 1.2 Setup for Development

Once the SDK is split into two parts the Rational Team Concert Extensions Workshop can no longer be performed using just one Eclipse Workspace. An SDK is set up as a Target Platform in the Plug-in Development section. Since the SDK’s are now split, it is necessary to have two target platforms. Since it is not possible to have more than one Target platform active in one Eclipse workspace it is not possible to launch a server for debugging while running an Eclipse client from the same workspace.

The RTC Extensions workshop will have to be changed to set up two separate workspaces.

  • One workspace will have to be set up with the RTC Server SDK as active Target Platform, for example using the path: C:\RTC603Dev\Workspaces\Dev1\Server
  • The other  workspace will have to be set up with the RTC Client SDK as active Target Platform, for example using the path: C:\RTC603Dev\Workspaces\Dev1\Client

Both workspaces will require to be set up as described in the RTC Extensions workshop document in section 1.2 Setup for Development.However, you will set up different target platforms in this step. Using the Server SDK for the server development workshop and the Client SDK for the Client development workspace.

Please note, it is a good idea to configure Eclipse to use an external browser as well in this step.

Changes to section: 1.3 Setup the RTC Tomcat Server

I am modifying the WorkshopSetup tool and data to setup the RTC project named RTC Extension Workshop to support an easier setup for the two workspaces. Basically two separate RTC Repository workspaces will be available. One will provide the launch, the configurations and the components needed to develop the RTC Eclipse server extension part of the workshop. The other one will provide the launch and the components needed to develop the RTC Eclipse client extension part of the workshop.

As long as this is not yet available it is possible to start with the existing setup tool and the related repository workspace and to load that into the two Eclipse workspaces. One workspace has to be set up with the RTC Client SDK will be used for development of the client part. The other with the RTC Server SDK set up is used to develop the server parts. When performing the workshop it will be necessary to work with the two workspaces and use one for all the server related tasks and the other one with the client related tasks. When Accepting changes into these workspaces it is necessary to understand what is part of the client and what is part of the server or what is shared. The image below shows what belongs to what.

  • The parts colored in blue are only related to server development
  • The parts colored in yellow are only related to client development
  • The uncolored parts are related to client and server development

client-server-common

Make sure to keep in mind which parts of the code are relevant for what. As an example, the project net.jazz.rtcext.workitem.extensions.ide.ui will not compile in the server development workspace. Similarly the net.jazz.rtcext.workitem.extensions.service project will not compile in the client development workspace.

Changes to section: 1.4 Complete Setup of Your RTC Eclipse Client

After Loading the repository workspace you have the choice to split the information into a sever part and a client part. For example you can duplicate RTC Extension Workshop Configuration and create one that only contains the client launches. Or you keep everything as it is and basically close the project areas you don’t need and ignore launches not needed. This is the easiest approach until a new Extension Workshop is available.

The initial step of copying the files services.xml and scr.xml is only needed in the server workspace. So when copying and importing, copy the files services.xml and scr.xml from your server’s ccm application in the installs\JazzTeamServer\server\conf\ccm folder into the RTC Extension Workshop Configuration project into the folder conf/jazz in the server development workspace.

When importing the plugins and features import the following into the server workspace:

  • com.ibm.team.common.tests.utils
  • com.ibm.team.jazz.foundation.server.licenses.enterprise-ea (or com.ibm.team.licensing.product.clm)
  • com.ibm.team.licensing.product.rtc-standalone

When importing the plugins and features import the following into the client workspace:

  • com.ibm.team.rtc.client.feature

Other considerations

As already mentioned, make sure to keep track which workspace you are working in and keep in mind that the server development part will not work in the client development workspace and vice versa.

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.

Summary

We have major changes coming up in the RTC Extension development area. The RTC Extension workshop needs to be adjusted and parts of the workshop lab needs to be reorganized and rewritten. This post explains what to consider for experienced users. Once there is an update to the Extension workshop lab material this post will be updated.

As always, I hope this helps users out there and saves them some time.

Posted in extending, Jazz, RTC, RTC Automation, RTC Extensibility | Tagged , , , , , , , | 15 Comments

The RTC Work Item Command Line on Bluemix


I was talking to a customer recently. They are using the WorkItem Command Line for some automation purposes. Since this can trigger e-mail notifications to a huge amount of users they wanted to use the new Skip Mail save WorkItem Parameter introduced in RTC 6.0 iFix3.

I had the time and went ahead implementing it. The resulting source code is available on IBM Bluemix DevOps Services in the project Jazz In Flight

ibm-bluemix-devops-services-2016-10-24_17-55-35

Access the Source Code

License

The post contains published code, so 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. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

RTC SCM Access

In the project you can access the source code of several extensions and automation I have created over the years. If you click Edit Code and you are not yet member of the project, you have to request access which I will allow.

The project contains a Stream called RTC Extensions with several components. One of the components is Work Item Command Line.

configure-eclipse-request-access-2016-10-24_18-13-14

To configure your RTC Eclipse client follow the instructions in the Configure eclipse client link. You can then create yourself a repository workspace and download the code. Please use the tracking and planning section (work items) if you want to do any changes to coordinate with me.

Changes

The current version uploaded there contains the capabilities described in A RTC WorkItem Command Line Version 3.0 plus a variety of bug fixes and a new switch /skipEmailNotification to disable work item update notification for the commands that modify work items such as

  • update
  • importworkitems
  • migrateattribute

The feature to suppress work item update notification is implemented in RTC 6.0 iFix3 where a new Skip Mail save WorkItem Parameter was introduced in RTC. When this additional save parameter is provided, the work item change does not trigger a work item change notification mail.The adoption in the WorkItem Command Line is done in a way that the implementation does not break the older API.  It introduces the additional save parameter value into the work item command line source code as new String constant instead of referencing the constant in the API. This way the WCL can be compiled with RTC Plain Java Client Library versions of RTC prior to 6.0 iFix3. If the WCL is run with versions earlier than 6.0 iFix3, e-mail notification is not suppressed. The behavior does not change in such versions of RTC and the additional save parameter is simply ignored.

Additional Download

You can also download the latest version 3.4 here:

Please note, there might be restrictions to access Dropbox and therefore the code in your company or download location.

Usage and install

Please see the posts A RTC WorkItem Command Line Version 3.0.

For the general setup follow the description in A RTC WorkItem Command Line Version 2.

For usage follow the description in A RTC WorkItem Command Line Version 2 and in A RTC WorkItem Command Line Version 2.1. Check the README.txt which is included in the downloads.

Summary

The work item command line is now available on IBM Bluemix Dev Ops Services and can be accessed and worked on there.

Posted in BlueMix, cloud, RTC, RTC Automation, RTC Extensibility | Tagged , , , , | Leave a comment

Using the Work Item Server API to create Work Items


How can one create a work item in a follow up action? How to link such a work item to the work item that was just saved? If you are interested in some more details using the work item server API continue reading.

These are questions that come up often in the Jazz Forum. There are several answers already in the forum, but I did never take the time to publish anything here.  Lets change that now.

License

The post contains published code, so 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. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, 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.

Which API’s are available in the server SDK and which should I use?

The Java API available in the server SDK is the common API and the server API. The common API usually is in packages with *.common.* in the namespace. The server API usually is in packages named with *.server.* in the namespace.The Interfaces names available in the RTC SDK also often have a postfix such as Common or Server or Service. As example the interface

com.ibm.team.workitem.common.IWorkItemCommon

is an important common API for work item manipulation.

Another example is the interface

com.ibm.team.workitem.service.IWorkItemServer

which is is an important server API for work item manipulation.

It is important to note, that the common API is also available in the client SDK. This is important, because the common API can then be used in client code as well as in server extensions. The client SDK and the Plain Java Client Libraries package the common API and also provide a client API. The client API usually is in packages named with *.client.* in the namespace. Like the in the pattern above the interface names often have a postfix Client in the name.

So, the interface

com.ibm.team.workitem.common.IWorkItemCommon

is available in the server SDK/API as well as in the client SDK/API and an important common API for work item manipulation.

The interface

com.ibm.team.workitem.client.IWorkItemClient

is only available in the client SDK and the Plain Java Client Libraries.

It is also important to note, that he common Interfaces are usually included in the Client and Server Interfaces. As an example the interface IWorkItemServer extends IWorkItemCommon

public interface IWorkItemServer extends IWorkItemCommon {

Similar in the client API with IWorkItemClient

public interface IWorkItemClient extends IWorkItemCommon {

This pattern repeats across the available APIs. The specific client and server interfaces like IWorkItemServer and IWorkItemClient just add a few very specific client side capabilities.

TIP – Try to use the Common API over the specific client or server APIs

If you can, you should use the common API and prefer it over the more specific ones. That way it is possible to use a lot of code in both contexts. Unfortunately I became aware of the importance of this too late and a lot of the example code on this blog uses the more specific client and server interfaces. So look at the examples and always check if there is a common interface you could use. Fall back to the client or server related API if the common API does not have what is needed.

Creating a work item in the Server

In the client API it is possible to use the class com.ibm.team.workitem.client.WorkItemOperation which deals with error handling. As we have learned in the paragraph before, this is client only API and not available in the server API.

For most of the operations needed to work with the data for a work item, the common interface IWorkItemCommon. Examples for methods likely needed are

  • IWorkItemCommon.findAttribute()
  • IWorkItemCommon.findWorkItemType()
  • IWorkItemCommon.resolveEnumeration()
  •  IWorkItemCommon.findCategories()
  •  IWorkItemCommon.findCategoriesOfProcessArea()

To create the work item on the server, you have to use IWorkItemServer.createWorkItem2(), then set the attributes and finally use IWorkItemServer.saveWorkItem3(), IWorkItemServer.saveWorkItem2() or IWorkItemServer.saveWorkItems() to save the work item(s). Which one you use depends on what needs to be saved.

Here some code that I used in an example follow-up action

/**
 * @param thisItem
 * @param workItemType
 * @param someAttribute
 * @param someLiteral
 * @param parsedConfig
 * @param monitor
 * @return
 * @throws TeamRepositoryException
 */
private IWorkItem createWorkItem(IWorkItem thisItem,
		IWorkItemType workItemType, IAttribute someAttribute,
		ILiteral someLiteral, ParsedConfig parsedConfig,
		IProgressMonitor monitor) throws TeamRepositoryException {

	IWorkItemServer fWorkItemServer = this.getService(IWorkItemServer.class);

	IWorkItem newWorkItem = fWorkItemServer.createWorkItem2(workItemType);

	XMLString targetSummary = thisItem.getHTMLSummary();
	XMLString newSummary = targetSummary.concat(addition);
	newWorkItem.setHTMLSummary(XMLString.createFromXMLText(newSummary
			.getXMLText()));
	ICategoryHandle category = thisItem.getCategory();
	if (category != null) {
		newWorkItem.setCategory(thisItem.getCategory());
	}

	IIterationHandle iteration = thisItem.getTarget();
	if (iteration != null) {
		newWorkItem.setTarget(iteration);
	}
	if (null != workItemType) {
		newWorkItem.setValue(someAttribute,someLiteral.getIdentifier2() );
	}

	Set additionalParams = new HashSet();
	additionalParams.add(ICreateTracedWorkItemsParticipant.CREATE_TRACED_WORKITEMS_PARTICIPANTS_ACTION_SAVENEW);

	fWorkItemServer.saveWorkItem3(newWorkItem, null, null, additionalParams);
	return newWorkItem;
}

Please note, that rules apply in the server  as well. Required attributes will be required and need to be provided to be able to save. The server operation runs in a context with specific privileges and it has only the permissions provide by the user context.

The next part of the code is for creation of tracks links and saving the links with a work item. The idea is t

/**
 * This method manages creating and linking the work items and saving the
 * new references.
 * 
 * @param thisWorkItem
 * @param monitor
 * @throws TeamRepositoryException
 */
private void createAndLinkPhaseWorkItems(IWorkItem thisWorkItem, IProgressMonitor monitor) throws TeamRepositoryException {

	IWorkItemServer fWorkItemServer = this.getService(IWorkItemServer.class);

	// Create the work items and the links and return the references
	List newItems = createWorkItems(thisWorkItem, monitor);
	IWorkItemReferences sourceReferences= fWorkItemServer.resolveWorkItemReferences(thisWorkItem, monitor);
	for (Iterator iterator = newItems.iterator(); iterator.hasNext();) {
		IWorkItem targetItem = (IWorkItem) iterator.next();
		ILinkType tracksLinkType= ILinkTypeRegistry.INSTANCE.getLinkType(WorkItemLinkTypes.TRACKS_WORK_ITEM);
		sourceReferences.add(tracksLinkType.getTargetEndPointDescriptor(), IReferenceFactory.INSTANCE.createReferenceFromURI(Location.namedLocation(targetItem, getPublicRepositoryURL()).toAbsoluteUri()));
	}
	Set additionalParams = new HashSet();
	additionalParams.add(ICreateTracedWorkItemsParticipant.CREATE_TRACED_WORKITEMS_PARTICIPANTS_ACTION_SAVEREFERENCES);

	// Save the work item we created new linked items for
	IStatus saveStatus = fWorkItemServer.saveWorkItem3(thisWorkItem,
			sourceReferences, null, additionalParams);
	// Handle the error
	if (!saveStatus.isOK()) {
	
	}

Summary

I wanted to post that for a long time, finally I was able to take the time. I hope this helps someone out there starting with extending and automating RTC.

Posted in Jazz, RTC, RTC Automation, RTC Extensibility | Tagged , , , | Leave a comment

Scaling the Collaborative Lifecycle Management (CLM) solution across an enterprise


Scaling the Collaborative Lifecycle Management (CLM) solution across an enterprise, is the title of the webinar Tim and I presented recently. Tim and I have worked on this content for a while and consider it important. Please also see  Tim’s related post Getting to a right-sized Jazz environment. There is additional reading below.

Objectives of the presentation

Scaling the v6.0.x Collaborative Lifecycle Management (CLM) solution across an enterprise often includes multiple instances of a given Jazz application. What multi-Jazz application options are available and what are the considerations?

  • What topologies and general multi-Jazz application options are available
  • How Jazz applications such as Change Configuration Management (CCM), Quality Management (QM) and Requirements Management (RM) relate to a Jazz Team Server (JTS)
  • The impact, advantages and disadvantages of multiple CLM Applications
  • What to consider when scaling and developing usage models adopting one of these deployment options to avoid surprises

If you are interested in this presentation, you can find the replay of the webinar here in the Rational Team Concert Enlightenment Series.

The slides are shared here.

Additional Reading

Posted in Jazz | 5 Comments