This is the forth post in the series around very fine grained access control permissions for work items and SCM versionables. It explains the last requirement, which was to be able to set the custom attributes on elements in the SCM system using the RTC API.
See the problem description in the first post of the series
Related posts
The posts in this series are:
- Manage Access Control Permissions for Work Items and Versionables
- Setting Access Control Permissions for Work Items
- Setting Access Control Permissions for SCM Versionables
- Setting Custom Attributes for SCM Versionables – this post
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 5.0.2 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.
The code in this post uses common libraries/services that are available in the Plain Java Client, Eclipse client and Jazz Eclipse server API. If client or server API is used, this is stated.
Note, some capabilities where only finalized in RTC 6.0.1 and are not available in versions before. Especially custom attributes for components and potentially for items other than SCM versionables.
Custom Attributes for SCM Versionables
Rational Team Concert 5.0.2 introduces support for creating custom attributes on source file versions.
The attributes can be set for every version of the SCM versionable. Dependent on the definition the attribute can be missing or different on different versions. This is different to the behavior we have seen in the post Setting Access Control Permissions for SCM Versionables, where the read access permission applies to all versions of the item.
The image below shows for which SCM elements custom attributes are available and how they can be set up to behave.

The behavior is important, because there are several very distinct requirements. For example it is desirable to be able to set some attribute only on one specific version. As an example to classify safety critical source code that needs special testing if changed, to allow for auditing. For others it is better to keep a value, once it is set.
Working with Custom Attributes for SCM Versionables
The following code shows how to work with the custom attributes for versionable handles. Please note, that there is no way to access these attributes in the RTC UI at the moment. They are accessible in the API otherwise they can only be set and read in the RTC SCM Commandline.
Getting the IScmService
To set custom attributes for versionables, requires the IScmService class com.ibm.team.scm.common.IScmService. As described in the post Setting Access Control Permissions for SCM Versionables, It is easy to get this service in the Server API, by basically using
IScmService fScmService = getService(IScmService.class);
However, in the Client API, this is not accessible as client library using the usual getClientLibrary() call.
I searched the client API and found about 6 different ways how this interface was requested by the product and test code in the RTC client SDK. For various reasons I picked the following approach and wrapped it into a utility class.
/*******************************************************************************
* Licensed Materials - Property of IBM
* (c) Copyright IBM Corporation 2015. 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.access.control.client;
import com.ibm.team.repository.client.ITeamRepository;
import com.ibm.team.repository.client.internal.TeamRepository;
import com.ibm.team.scm.common.IScmService;
public class ScmServiceClient {
/**
* Get the SCM Service in a client application
*
* @param teamRepository
* @return
*/
public static IScmService getSCMService(ITeamRepository teamRepository) {
IScmService scmService = (IScmService) ((TeamRepository) teamRepository)
.getServiceInterface(IScmService.class);
return scmService;
}
}
Note that the method uses the internal interface com.ibm.team.repository.client.internal.TeamRepository and not the interface ITeamRepository that is usually used to get a client library. The method getServiceInterface() is not exposed on ITeamRepository, so it is necessary to cast the ITeamRepository object to the actual class that implements the interface.
Listing Custom Attributes
See this post for a hint.
Setting Custom Attributes
The following code sets the custom attributes for versionable handles.
It basically gets the attributes available on the element. The data is returned as a hashmap with the attribute name being the key. This can be used for printing the data as well as shown below.
The code puts the attribute and its value in the hashmap and then this nap is passed to be saved.
/**
* Set a specific attribute of versionable handles
*
* @param vhandles
* @param attributeName
* @param attributeValue
* @param scmService
* @throws TeamRepositoryException
*/
public static void setAttribute(IVersionableHandle[] vhandles,
String attributeName, String attributeValue, IScmService scmService )
throws TeamRepositoryException {
ICustomAttributeList[] versionableAttributesList = scmService
.fetchCustomAttributesForVersionable(vhandles, null);
for (int i = 0; i < versionableAttributesList.length; i++) {
ICustomAttributeList attributeList = versionableAttributesList[i];
Map<String, Object> attributeMap = attributeList
.getCustomAttributes();
attributeMap.put(attributeName, attributeValue);
attributeList.setCustomAttributes(attributeMap);
scmService.saveCustomAttributesForVersionable(vhandles[i],
attributeList, null);
}
}
As shown in the post Setting Access Control Permissions for SCM Versionables it is easy to create the required array if only one versionable handle is available using this code.
IVersionableHandle[] vhandles = new IVersionableHandle[] { versionableHandle };
Similar, it is easy to use the code here if the available data is a change set, by using the same technique as shown in the post Setting Access Control Permissions for SCM Versionables.
In both case, it is possible to create the array with all elements that need the change and then run the operation for all. This is also the most efficient way.
Removing Custom Attributes
Custom attributes can be removed by removing an attribute entry from the map or creating a map that does not contain this attribute. It is possible to erase all custom attributes by setting an empty map like below:
ICustomAttributeList[] versionableAttributesList = scmService
.fetchCustomAttributesForVersionable(vhandles, null);
for (int i = 0; i < versionableAttributesList.length; i++) {
ICustomAttributeList attributeList = versionableAttributesList[i];
attributeList.setCustomAttributes(new HashMap<String, Object>());
scmService.saveCustomAttributesForVersionable(vhandles[i],
attributeList, null);
}
I have not tested this, but I assume that attributes that are defined to have a default value and are automatically applied, will be recreated with the default value when deleting them from the map.
Getting Custom Attributes
The next code snippet shows how to get or accesses the custom attributes and how to print them. It basically gets the map and then iterates the contained keys to access the attributes:
/**
* Print the attributes for an array of versionable handles
*
* @param vhandles
* @param scmService
* @throws TeamRepositoryException
*/
public static void printAttributes(IVersionableHandle[] vhandles, IScmService scmService,String message)
throws TeamRepositoryException {
System.out.println(message);
ICustomAttributeList[] versionableAttributesList = scmService
.fetchCustomAttributesForVersionable(vhandles, null);
for (int i = 0; i < versionableAttributesList.length; i++) {
ICustomAttributeList attributeList = versionableAttributesList[i];
Map<String, Object> attributeMap = attributeList
.getCustomAttributes();
printAttributes("Attributes: ",attributeMap);
}
}
/**
* @param message
* @param attributeMap
*/
private static void printAttributes(String message, Map<String, Object> attributeMap) {
System.out.print(message + " - ");
Set keys = attributeMap.keySet();
if(keys.isEmpty()){
System.out.print("No");
}
System.out.println(" attributes found:");
for (String key : keys) {
Object value = attributeMap.get(key);
printAttributeValue(message, key, value);
}
}
/**
* @param message
* @param key
* @param value
*/
private static void printAttributeValue(String message, String key, Object value) {
if (value != null) {
System.out.println(message + ": " + key
+ " value: " + ((String) value));
} else {
System.out.println("Version Attribute: " + key
+ " no value");
}
}
Getting Available Custom Attributes
Please see How to retrieve the set of allowed custom SCM attributes via Plain Java Client API?
Custom Attributes for Other SCM Elements
The API to get or set custom attributes for other objects, is similar to the API for versionables. Since they are unique objects and don’t have different versions, there is only one set of custom attributes available for them.
Please note, the full functionality for these objects only became available in 6.0.1
Custom Attributes for Streams
To set custom attributes for streams, since 6.0.1 the common API provides the interface
com.ibm.team.scm.service.internal.ScmService.setWorkspaceCustomAttributes(IWorkspaceHandle, IGenericAttributes, String[], ISynchronizationTimes[], IRepositoryProgressMonitorHandle)
to set custom attributes.
The interface com.ibm.team.scm.common.IWorkspace provides the method
com.ibm.team.scm.common.IWorkspace.getCustomAttributes()
to get the custom attributes of the stream.
Please note, that the data is cached, if you want accurate information refresh the object e.g. using com.ibm.team.scm.client.IWorkspaceConnection.refresh(IProgressMonitor).
The code to set and get the custom attributes would look like below:
IWorkspaceManager wm = SCMPlatform.getWorkspaceManager(teamRepository);
IWorkspaceSearchCriteria criteria = IWorkspaceSearchCriteria.FACTORY.newInstance().setKind(IWorkspaceSearchCriteria.STREAMS);
criteria.setExactName("JKE Banking Integration Stream");
List connection = wm.findWorkspaces(criteria, Integer.MAX_VALUE, monitor);
IWorkspaceHandle streamHandle = connection.get(0);
IWorkspaceConnection wcStream = wm.getWorkspaceConnection(streamHandle, monitor);
IWorkspace streamConnection = wcStream.getResolvedWorkspace();
IScmService scmService = ScmServiceClient.getSCMService(teamRepository);
Map<String,Object> customAttributes=new HashMap<String,Object>();
customAttributes.put(CUSTOM_ATTRIBUTE, "Test");
String[] attributesToClear = new String[] { CUSTOM_ATTRIBUTE };
wcStream.refresh(monitor);
printAttributes("Stream AttributesInitial", streamConnection.getCustomAttributes());
// Set the custom attributes
IGenericAttributes streamAttributes = IGenericAttributes.FACTORY.newInstance(customAttributes);
scmService.setWorkspaceCustomAttributes(streamHandle, streamAttributes, null, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
wcStream.refresh(monitor);
printAttributes("Stream Attributes", streamConnection.getCustomAttributes());
// Clear the custom attributes
scmService.setWorkspaceCustomAttributes(streamHandle, null, attributesToClear, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
wcStream.refresh(monitor);
printAttributes("Stream AttributesAfterClear", streamConnection.getCustomAttributes());
Custom Attributes for Snapshots
To set custom attributes for snapshots, since 6.0.1 the common API provides the interface
com.ibm.team.scm.service.internal.ScmService.setBaselineSetCustomAttributes(IBaselineSetHandle, IGenericAttributes, String[], ISynchronizationTimes[], IRepositoryProgressMonitorHandle)
to set custom attributes.
In addition, in 6.0.1, the interface com.ibm.team.scm.common.IBaselineSet provides the method
com.ibm.team.scm.common.IBaselineSet.getCustomAttributes()
to get the custom attributes of the snapshot.
Please note, that the data is cached, if you want accurate information refresh the object e.g. using the IItemManager and the IItemManager.REFRESH flag to get the latest information.
The code to set and get the custom attributes would look like below:
IBaselineSetSearchCriteria bScriteria = IBaselineSetSearchCriteria.FACTORY.newInstance();
bScriteria.setExactName("TestSnapShot");
List baselineSetHandles = SCMPlatform.getWorkspaceManager(teamRepository).findBaselineSets(bScriteria, 100, monitor);
BaselineSetHandle snapShotHandle = (BaselineSetHandle) baselineSetHandles.get(0);
IBaselineSet snapShot = (IBaselineSet) teamRepository.itemManager().fetchCompleteItem(snapShotHandle,IItemManager.REFRESH,monitor);
printAttributes("Snapshots AttributesInitial", snapShot.getCustomAttributes());
scmService.setBaselineSetCustomAttributes(snapShotHandle, custAttributes, null, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
snapShot = (IBaselineSet) teamRepository.itemManager().fetchCompleteItem(snapShotHandle,IItemManager.REFRESH,monitor);
printAttributes("Snapshots Attributes", snapShot.getCustomAttributes());
scmService.setBaselineSetCustomAttributes(snapShotHandle, null, attributesToClear, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
snapShot = (IBaselineSet) teamRepository.itemManager().fetchCompleteItem(snapShotHandle,IItemManager.REFRESH,monitor);
printAttributes("Snapshots AttributesAfterClear", snapShot.getCustomAttributes());
Custom Attributes for Baselines
To set custom attributes for streams, since 6.0.1 the common API provides the interface
com.ibm.team.scm.service.internal.ScmService.setBaselineCustomAttributes(IBaselineHandle, IGenericAttributes, String[], ISynchronizationTimes[], IRepositoryProgressMonitorHandle)
to set custom attributes for snapshots.
In addition, in 6.0.1, the interface com.ibm.team.scm.common.IBaseline provides the method
com.ibm.team.scm.common.IBaseline.getCustomAttributes()
to get the custom attributes of the baseline.
Please note, that the data is cached, if you want accurate information refresh the object e.g. using the IItemManager and the IItemManager.REFRESH flag to get the latest information.
The code to set and get the custom attributes would look like below:
IBaselineHandle baseLineHandle = buildComponent.getInitialBaseline();
IBaseline baseLine = (IBaseline) teamRepository.itemManager().fetchCompleteItem(baseLineHandle,IItemManager.REFRESH,monitor);
printAttributes("Baseline AttributesInitial", baseLine.getCustomAttributes());
scmService.setBaselineCustomAttributes(baseLineHandle, custAttributes, null, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
baseLine = (IBaseline) teamRepository.itemManager().fetchCompleteItem(baseLineHandle,IItemManager.REFRESH,monitor);
printAttributes("Baseline Attributes", baseLine.getCustomAttributes());
scmService.setBaselineCustomAttributes(baseLineHandle, null, attributesToClear, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
baseLine = (IBaseline) teamRepository.itemManager().fetchCompleteItem(baseLineHandle,IItemManager.REFRESH,monitor);
printAttributes("Baseline AttributesAfterClear", baseLine.getCustomAttributes());
Custom Attributes for Components
To set custom attributes for components, since 6.0.1 the common API provides the interface
com.ibm.team.scm.service.internal.ScmService.setComponentCustomAttributes(IComponentHandle, IGenericAttributes, String[], ISynchronizationTimes[], IRepositoryProgressMonitorHandle)
In addition, in 6.0.1, the interface com.ibm.team.scm.common.IComponent provides the method
com.ibm.team.scm.common.IComponent.getCustomAttributes()
to get the custom attributes of the component.
Please note, that the data is cached, if you want accurate information refresh the object e.g. using the IItemManager and the IItemManager.REFRESH flag to get the latest information.
The code to set and get the custom attributes would look like below:
printAttributes("Component AttributesInitial", buildComponent.getCustomAttributes());
scmService.setComponentCustomAttributes(buildComponent, custAttributes, null, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
buildComponent = (IComponent) teamRepository.itemManager().fetchCompleteItem(buildComponent,IItemManager.REFRESH,monitor);
printAttributes("Component Attributes", buildComponent.getCustomAttributes());
scmService.setComponentCustomAttributes(buildComponent, null, attributesToClear, null, IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor));
buildComponent = (IComponent) teamRepository.itemManager().fetchCompleteItem(buildComponent,IItemManager.REFRESH,monitor);
printAttributes("Component AttributesAfterClear", buildComponent.getCustomAttributes());
Summary
This post explains how to set custom attributes for SCM elements. As always, I hope this is useful to someone out there.