WorkItem Command Line and RTC/EWM Extensions Workshop for 7.0.2 SR1

Work Item Command Line for 7.0.2 SR1

The Workitem Command Line had dependencies to the plain Java Client Libraries, including to Log4J1 in a few places. This breaks the Work Item Command Line for IBM Engineering Lifecycle Management 7.0.2 SR1 especially IBM Engineering Workflow Management 7.0.2 SR1 (EWM). WCL 5.3.1 and earlier will not work with the 7.0.2 SR1.

It was requested to support 7.0.2 SR1 with the WorkItem Command Line. I had a look and was able (I think) to update the code of the WCL to work with the new Plain Java Client Libraries. This removes the dependencies to Log4J1 and change the functionality to use Log4J2. The code is on a different branch named Log4j2, because it is incompatible with previous versions of EWM. A new pre-release was created and is available here as Work Item Command Line 6.0 prerelease. I have only done minimal testing. If you have an opportunity to run it, please report issues.

EWM/RTC Extensions Workshop for 7.0.2 SR1

To be able to perform the updates I had to perform (most parts of) Lab 1 of the Rational Team Concert Extensions Workshop. The workshop still works. There are some smaller issues and here is my erratum so far.

  • I downloaded Eclipse IDE 2022-06 R and installed EWM into it. Unfortunately there is an issue when connecting to the EWM server. I have not been able to look into this issue. The error is “Could not get value of field private transient sun.util.calendar.BaseCalendar$Date java.util.Date.cdate in 2022-07-31 09:37:08.301” . I have not been able to overcome this yet. However, you can download and install an Eclipse EWM Client and use that instead. Also see this discussion and suggested resolutions.
  • When adding the plugins to the search path the UI has changed and the menu item in the Eclipse version above is named “Add to Java Workspace Scope”.
  • When trying to create the Test Database with the JUnit launch, the test ran out of memory. I increase the memory settings in the launch.

Summary

The changes to the ELM 7.0.2 SR1 break the Workitem Command Line and require a new setup of the Extensions workshop to develop extensions. The WorkItem Command Line is available as a prerelease for ELM 7.0.2 and the Extensions Workshop seems to be working with minor limitations.

EWM/RTC Plain Java Client Libraries and Maven

I have worked with Maven applications using the RTC Plain Java Client libraries often recently. It has not always been fun, I have been struggling with Maven. I have been struggling with the Plain Java Client Libraries and Maven interacting. In this bog, I will try to share some things I have learned over the time, and recently, that you can use when working with Maven, especially in the context of EWM/RTC automation using the Plain Java Client Libraries.

Maven basics

How to install Maven is documented in this link. I do not intent to rewrite this documentation. I just want to emphasize some things that I always run into.

  1. Using Maven, requires a Java JDK. A JRE is not sufficient. Where to download a valid, supported, IBM JDK, is explained below.
  2. When using Maven in the command line, make sure to have the JAVA_HOME set to the correct JDK.
  3. When using Maven in the command line, make sure to have Maven added to the path.
  4. When using Maven with the Eclipse IDE, make sure to have an up to date Maven installed. I usually download the recent version, install it to work with a command line and then add that install to Eclipse.
  5. When using Maven with the Eclipse IDE, there is still the need to have a compatible JDK configured. Make sure to go to Preferences>Java>Installed JRE’s, add the JDK and set it as active. Then go to Preferences>Java>Installed JRE’s>Execution Environments configure an environment with the JDK. E.g. JavaSE-1.8 for EWM 7.0.x.
  6. When using Maven for a project in an Eclipse IDE right click on the project
    1. Use Maven>Update Project to make sure Eclipse is configured correctly.
    2. Use Run As>Maven clean on the Project or the pom.xml.
    3. Use Run As>Maven install on the Project or the pom.xml.
    4. Sometimes the Eclipse build mechanism seems to be in conflict with Maven, Project>Clean might help.
  7. Sometimes weird things happen. Run maven with -e or -X to see more details.
  8. Sometimes weird things happen, if all fails, consider to delete the local repository folder in the .m2 folder in your user directory.

Maven and the EWM Plain Java client libraries

When working with EWM/RTC automation based on the plain java client libraries, it is possible to download a valid, supported, IBM JDK on the same page where the Plain Java Client Libraries are hosted. When working with EWM/RTC and the Plain Java Client Libraries, the items below show the most important files to download to work with the Plain Java Client Libraries. To get them go to the All downloads tab for the version required. As an example for EWM 7.0.2 go to https://jazz.net/downloads/workflow-management/releases/7.0.2?p=allDownloads.

  1. Get the 10-Free Developers License Activation Kit. Scroll down to the section License Keys and download the 10-Free Developers License Activation Kit. It is very useful to run EWM test systems.
  2. Get the Client for Eclipse. Scroll to the Plain .zip Files section. Download the Client for Eclipse for your architecture.
  3. Get the plain Java Client Libraries. In the Plain .zip Files section download the Plain Java Client Libraries and the API documentation.
All Downloads page

The JDK

The download for the EWM Client for Eclipse contains the required JDK in the folder jazz/jdk. Unpack the EWM client and use the JDK for your development with the Eclipse Client Libraries and Maven.

The trouble with Maven and the Plain Java Client Libraries.

Unfortunately there is no Maven library for the Plain Java Client Libraries. This is a problem, because there is no real good solution (that I could find) to work with Maven and libraries that do not have a maven repository.

In some projects, I was able to get away with working with Maven and the Plain Java Client Libraries, using an Eclipse User Library with the Plain Java Client Libraries. This works, if at all, only in the Eclipse IDE.

In a recent project this solution was not manageable. I was unable to compile, or I was able to compile, but running the application failed with class not found exceptions. I got it working on my laptop, but we were unable to get it working for a colleague. We lost days.

My usual strategy of using <put your most popular internet search engine here> to find solutions did not really help. Solutions that I found where cryptic, not understandable and/or did not work.

Packaging the Plain Java Client Libraries as local Maven repository.

I finally found this script https://github.com/cokeSchlumpf/mvn-rtc-java-api that allows packaging the plain java client libraries as a maven repository and include that in the application POM file. This allows shipping the Plain Java Client Libraries as Maven repository with the application and its code to be able to run Maven in Eclipse as well as on the command line.

Although the script finally was a life saver, I had some tough learning to get things right. The main issue was that it is a Bash script and my Windows system does not Bash. I tried installing Cygwin64 but realized that I would have to install all kind of stuff to get that working. As I had recently done some other EWM and containerization related work on my NAS, I ended up setting up the required Maven and JDK on my NAS system. I was able to run the script from there 7Zip the result and upload it to my development environment.

In my first attempt, unfortunately, I did not pay enough attention to the format of the dependencies. The dependencies to external libraries has the format <groupId>:<artifactId>:<version>.

# 6.0.2
export DEPENDENCIES="org.apache.james:apache-mime4j:0.6 commons-io:commons-io:1.2 org.apache.httpcomponents:httpclient:4.5 org.apache.httpcomponents:httpclient-cache:4.5 org.apache.httpcomponents:httpclient-win:4.5 org.apache.httpcomponents:httpcore:4.4.1 org.apache.httpcomponents:httpcore-ab:4.4.1 org.apache.httpcomponents:httpcore-nio:4.4.1 org.apache.httpcomponents:httpmime:4.5"

For whatever reason I did not realize that and only provided the <groupId>. This creates an invalid repository. The symptom is the warning message ‘The POM for …. is invalid, transitive dependencies (if any) will not be available’. It took a while to figure out what the reason was. I ended up recreating the repository using the following dependencies values for 7.0.1:

# 7.0.1
export DEPENDENCIES="org.apache.james:apache-mime4j:0.6 commons-io:commons-io:1.2 org.apache.httpcomponents:httpclient:4.5.6 org.apache.httpcomponents:httpclient-cache:4.5.6 org.apache.httpcomponents:httpclient-win:4.5.6 org.apache.httpcomponents:httpcore:4.4.10 org.apache.httpcomponents:httpcore-ab:4.4.10 org.apache.httpcomponents:httpcore-nio:4.4.10 org.apache.httpcomponents:httpmime:4.5.6"

It is totally possible that some of my attempts to fix the above problem made things more miserable. I just realized the severity of the issue when I merged my projects to one and still had the problem.

Please note, if you follow the script above, provide the repository and change the pom of your application and run

mvn clean install

the repository is copied into the local maven repository on your machine. It is stored in the user directory in the folder

.m2/repository/com/ibm/rtc/rtc-java-api

If you build a new version of the repository, make sure to delete the folder above, to make sure your new version is actually installed. Maven does not recognize a difference and will not replace the local files on its own. The reason is that there is no version change visible in the data. This holds true also for the machines of your fellow developers. So when recreating a new Plain Java Client Libraries maven repository with the script, make sure to delete the old local maven repository for the library rtc-java-api in you local .m2 folder as explained above. Then run

mvn clean install

This will recreate the maven library.

I finally succeeded with running

# 7.0.1
export DEPENDENCIES="org.apache.james:apache-mime4j:0.6 commons-io:commons-io:1.2 org.apache.httpcomponents:httpclient:4.5.6 org.apache.httpcomponents:httpclient-cache:4.5.6 org.apache.httpcomponents:httpclient-win:4.5.6 org.apache.httpcomponents:httpcore:4.4.10 org.apache.httpcomponents:httpcore-ab:4.4.10 org.apache.httpcomponents:httpcore-nio:4.4.10 org.apache.httpcomponents:httpmime:4.5.6"

./setup-repo.sh -l ./libs-7.0.1 -r ./repo -d "${DEPENDENCIES}" -v 7.0.1

I followed the readme and added the following to my pom.xml

	<!-- The maven dependency for the EWM Plain Java Client Libraries provided in a local repository -->
		<dependency>
			<groupId>com.ibm.rtc</groupId>
			<artifactId>rtc-java-api</artifactId>
			<version>7.0.1</version>
			<type>pom</type>
		</dependency>

and the repository:

<!-- The maven repository for the EWM Plain Java Client Libraries -->
<repositories>
    <repository>
        <id>project-repo</id>
        <releases>
            <enabled>true</enabled>
            <checksumPolicy>ignore</checksumPolicy>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <url>file://${project.basedir}/repo</url>
    </repository>
</repositories>

The location is based on a project property:

		<project.basedir>${basedir}</project.basedir>

So the files of the repository where copied and located in my Eclipse project in the folder repo in the project root folder.

The repository is bundled in the folder repo

Now it is possible to run Maven from within Eclipse as well as on the shell/command line and my project cleans, installs and liberty:run and the warning mentioned above is gone.

I can only suggest to use the mvn-rtc-java-api – Simple setup RTC Java Client API for Maven project. I would like to thank Victor and Michael for their great contribution. I can only suggest to use it for your purposes.

Whats Next?

I am a bit hesitant to use my personal NAS system as an extended Linux system for development. I will see if I can find some time to understand what the application does in detail and maybe rewrite it in Python. That would make it more operating system independent and allow broader usage.

Summary

As always, I hope that this post helps users out there to achieve their goal and saves some hours of work.

Work Item Command Line 4.3

I worked with a colleague on the Work Item Command Line who was adding a feature for usage with a customer. That colleague had also done some changes related to availability and performance running queries. These changes where merged back into the code. WCL was missing some capabilities that I always wanted to have. I had a quick look to understand how much effort hat would be and took the opportunity to implement these capabilities on the way. While doing so, some small enhancements where added and some defects where found and fixed. All that needed to be published as a new version of WCL.

Print a work item

New in Version 4.3

The latest release 4.3 is available here and has the following changes:

  • Readme.md updated
  • Readme documents for deployment in source code updated
  • Refactored the capability to create a string representation for a work item attribute, link or pseudo attribute (e.g. attachments) into a helper class WorkItemExportHelper
  • Migrated -exportworkitems to use the new helper class WorkItemExportHelper
  • Several fixes in -exportworkitems to
    • Enable error handling and make suppressing errors work
    • Introduce a new flag that exports all supported columns and links
    • If exporting all columns, order the attributes and links (except ID, Type and Summary that are by default at the beginning)
    • Checked functionality with newest OpenCSV
    • Refactoring class to make maintenance easier
  • Added a new command -printworkitem that prints the attributes, attachments and supported links of a work item
    • Using the WorkItemExportHelper and its capabilities
    • Also provides switch to print all attributes and links ordered as above
    • Exports the attachments to a provided folder
  • Added a new command -printtypeattributes that allows to get the attribute Id’s and Display Names for a given work item type in a project area
  • Added a command -validateoslclinks that validates OSLC links and their back links in other applications fixing missing back links
  • External library dependencies are added without a version number to allow newer versions

Disclaimer

Please keep in mind that the information in this blog is “as is”, unsupported, and may be outdated or inaccurate.

The Work Item Command Line (WCL) is not an officially supported application.

For information on released products, consult the product documentation, support tech notes, and the Jazz.net library.

Open Items

Some of the API used in the Work Item Command Line becomes deprecated.

  • Some changes especially for -importworkitems needed for versions of RTC e.g. 6.0.5 and later
    • These will likely not work with earlier versions of RTC
    • if you need that either try an earlier version of WCL such as 4.0 or 4.1 or open an issue and I could look into a backport
  • The Linking API in RTC has evolved and deprecates some API used in WCL
  • OpenCSV has evolved and newer versions deprecates some API used in WCL
    • OpenCSV requires a new library commons-lang3-3.1.jar
  • Migration to Maven might be something to consider

This is all not problematic yet, but needs to be addressed sooner or later.

License

WCL is released under the MIT License. See the License.txt and the license headers in the individual files.

Compatibility

This code has been used with RTC 4.x, 5.x  and 6.x with no or minimal changes and it is pretty safe to assume, that the code will work with newer versions of RTC to come.

An exception is the -importworkitems command that requires a library to use a mapping file. The capability to use the mapping file was moved into the plain Java Client libraries in RTC 6.0.5 as an internal class. To support work item import with the mapping moved to the Plain Java Client Libraries as internal API, the imports in ImportWorkItemsCommand where changed and the file com.ibm.team.workitem.rcp.core*.jar was removed from the jar file dependencies in the build path.

See Restore Compatibility to 6.0.4 and before for how to switch this back.

The code requires the RTC Plain Java Client Libraries.

The Export and import commands require additional external libraries that need to be downloaded and installed separately. See the document below.

Restore Compatibility to 6.0.4 and older

To support 6.0.5 and beyond the imports in ImportWorkItemsCommand where changed from:

com.ibm.team.workitem.rcp.core.internal.bugzilla.mappers.BugzillaMapping*

to: com.ibm.team.workitem.common.internal.importer.bugzilla.mappers.BugzillaMapping*

and the file com.ibm.team.workitem.rcp.core*.jar was removed from the jar file dependencies in the build path.

Follow the description in the sections beginning with Downloads how to get and rebuild the code. The steps in this section below are required to port WCL back to RTC 4.0.4 and earlier:

The original imports have been put back in past 4.0.3, but commented out. To enable the mapping for earlier versions of RTC, replace the imports *BugzillaMapping* with the versions commented out. Then add the com.ibm.team.workitem.rcp.core_*.jar file back in to the build path and add the required JAR file as below

From Work Item Command Line 4.1

The import commands of WCL can only provide the capability to use a mapping file by using a JAR file that only ships with the RTC Eclipse client and the SDK. The classes used for the mapping file capability are located in the library com.ibm.team.workitem.rcp.core.  Open the Install location of the RTC Eclipse client and search for com.ibm.team.workitem.rcp.core*. You should find a file names similar to this one: com.ibm.team.workitem.rcp.core_3.1.900.v20141010_0124.jar. The version numbers at the end could be different. Copy the JAR file into the into the libfolder of your version of WCL.

Download

The latest code can be downloaded from this GIT repository. The latest releases can be downloaded from here

There are different ways to download.

  • The easiest is to download the latest code as a zip file using the button Clone or download.
    • Use the option Download ZIP to download the code as ZIP file. Once the download finishes, browse the folder structure of the ZIP file. The top level contains the README.md file. An Eclipse project is contained in the folder com.ibm.js.team.workitem.commandline. This project can be used to develop the code and to generate an executable.
    • It is also possible to clone the repository and import the project using GIT. Clone the GIT project to your local file system. This requires GIT or some GIT GUI to be installed. How to use GIT is out of the scope of this blog. See the help how to set up GIT and how to use it with Eclipse.
  • It is also possible to download releases from the releases page. The zip code made available is in the same format as the one above can be used as described above. Note that the releases might be older, and there might be no release available for the latest code version.

See below how to import the enclosed project into Eclipse.

Some releases might contain a prepackaged executable for convenience e.g. named wcl-V4.3-20190117.zip. See the section Deploying the packaged application below for how to use this form of packaging. Please note that the prepackaged executable might not be available for all versions. The following sections explain how to create this executable. See the section Packaging the application for shipping for how to perform the packaging.

Prerequisites

Install a current Eclipse or RTC Eclipse client.

Install a current Java 1.8 JRE or Java 1.8 JDK set it as active in Eclipse as Installed JRE and Execution Environment.

Getting the code, install and deploy

Once you have installed such an environment do the following

Import the Code

  • Open the Java Perspective in Eclipse.
  • Import the project into Eclipse from the file system.
    • To import the ZIP file use File>Import, select Existing Projects into Workspace. Click Select archive file, browse to and select the ZIP file you downloaded. Import the enclosed Eclipse project com.ibm.js.team.workitem.commandline.
    • To import the GIT repository use the GIT perspective to add the local cloned repository and then import the
      project com.ibm.js.team.workitem.commandline.

Create a User Library for the Plain Java Client Libraries

  • Use Window>Preferences>Java>BuildPath>User Libraries and add a user library named PlainJavaApi .
  • Add the JAR files of the Plain Java Client Libraries for the version of RTC you are using.

Download and Install openCSV

Download and Install Apache commons-lang

Check the project and recompile

  • Select Project>Clean and clean the project that was just imported.
  • There should be no compiler errors or issues with the classpath

The project should now have built and compiled and show no errors.

Building the WCL or extract from a Release

Follow the description in the file ReadMe – HowToRelease.txt in the root folder of the project

  • To create a wcl.jar file
  • To crate a WCL/lib folder
  • To provide batch and license files

Follow the description in the file /lib/ReadMe.txt in the lib folder of the project

  • To provide the required libraries in the WCL/lib folder

Select the folder, for example C:\Temp\wcl\ and compress the file

  • Rename the archive file to wcl-Vx-YYYYMMDD.zip,
    where YYYY is the year, MM is the month and DD is the day
  • The file is now ready for publishing

Use the file wcl-Vx-YYYYMMDD.zip for shipping similar to the next section.

Deploying the packaged application

Assume a file was created following the steps above and the file is called
wcl-V4.3-20190117.zip. This binary contains WCL as JAR file and other information such as licenses and Readme files. It also contains script files to set the environment and run the Jar File.

The folder lacks libraries needed to execute that need to be provided.

To deploy from this file, create a new folder as deploy location for the automation prototype. In the description here we use C:\temp. It is possible to use any other folder. In this case replace the folder in the this description by the folder you chose.

Extract the binary wcl-V4.3-20190117.zip file into the location C:\temp. There should now be a folder C:\temp\WCL. The folder among others contains the files wcl.jar, wcl.bat, wcl.sh.

Get the libraries as described in Download and Install openCSV and Download and Install Apache commons-lang above, and rename them as described in /lib/ReadMe.txt.

Check the script file and make sure to provide a valid path to a folder containing the unzipped Plain Java Client Libraries and a recent Java 1.8 is available over a Java_Home.

Call WCL using the script files or call it as Jar File as described in said script files.

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’sand 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

This is only the first blog. I will try to provide a little bit more about the commands and the parameters soon.

As always, I hope this helps users out there. 

Please ask questions on in https://jazz.net/forum/questions/ and tag them rational-team-concert and wcl.

You can create issues in https://github.com/jazz-community/work-item-command-line/issues as well. 

Keep in mind this is off hours work and not officially supported.

Managing Contributor Licenses using the Java API

The question how to manage licenses using the plain java client libraries came up recently. There used to be a blog post in the internet that explained it, but that has been taken down. Questions on Jazz.net are not very clear for this, so I dug into the API myself. Here is the result.

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.

Solution

The service to access and assign licenses is the class com.ibm.team.repository.common.ILicenseAdminService.

Note that this class is not available as a client library such as other common and client services. The way to get this class in a client extension or a plain java API base application looks as follows:

ILicenseAdminService licenseAdminService = (ILicenseAdminService) ((IClientLibraryContext) teamRepository).getServiceInterface(ILicenseAdminService.class);

To access the class in a server extension like a pre-condition/advisor or a follow up action/participant is however using the typical com.ibm.team.repository.service.AbstractService.getService(Class) that is usually used e.g.:

ILicenseAdminService licenseService = getService(ILicenseAdminService.class);

The licensing code should work against each of the CLM applications JTS, CCM, QM, RM and should work for any available license.

This code can be used to print the license information for the available license types:

	IContributorLicenseType[] Licensetypes = licenseAdminService.getLicenseTypes();

	for (IContributorLicenseType iContributorLicenseType : Licensetypes) {
		System.out.println("License Type: ");
		System.out.println("License Type ID: " + iContributorLicenseType.getId());
		System.out.println("License Type Name: " + iContributorLicenseType.getName());
		System.out.println("License Type Description: " + iContributorLicenseType.getDescription());
		System.out.println("License Type ProductName: "	+ iContributorLicenseType.getProductName());
	}

The resulting list of licenses would look like below.

License Type: 
License Type ID: com.ibm.team.clm.stakeholder
License Type Name: Stakeholder
License Type Description: Diese Stakeholder-Lizenz ist zur Unterstützung von peripheren Benutzern gedacht, z. B. von externen Kunden, von Mitarbeitern der Benutzerunterstützung oder von Benutzern, die Arbeitselemente modifizieren und den Projektfortschritt beobachten müssen. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Stakeholder hat Lese- und Schreibzugriff auf Change Management sowie Lesezugriff auf Berichte und Planungsfunktionen, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten. Floating-Lizenzen werden dynamisch von einem Lizenzserver zugewiesen. Ein Benutzer mit zugewiesener Floating-Lizenz kann in den Pool der Benutzer aufgenommen werden, die die verfügbaren, auf dem Lizenzserver installierten Floating-Lizenzen gemeinsam nutzen. Führt ein solcher Benutzer eine Operation aus, für die diese Lizenz erforderlich ist, wird ihm vom Lizenzserver dynamisch eine Floating-Clientzugriffslizenz zugewiesen, wenn eine solche verfügbar ist. 
License Type ProductName: Rational solution for Collaborative Lifecycle Management
License Type: 
License Type ID: com.ibm.team.clm.practitioner
License Type Name: Practitioner
License Type Description: Diese Lizenz 'CLM Practitioner' ist für Anwender bestimmt, die aktiv an Projekten der Rational-Lösung für Collaborative Lifecycle Management mitwirken. Ein Benutzer mit zugewiesener Clientzugriffslizenz 'CLM Practitioner' hat vollen Lese- und Schreibzugriff auf das Änderungsmanagement, auf die Anpassung von Berichten, auf die Planung, auf das Softwarekonfigurationsmanagement, auf die Automation (Buildsystem), auf bestimmte Erweiterungen für IBM Unternehmensplattformen, auf Funktionen für Anforderungsdefinition und -management sowie Qualitätsmanagement und Lesezugriff auf Funktionen des Designmanagements, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational solution for Collaborative Lifecycle Management
License Type: 
License Type ID: com.ibm.team.rrc.reviewer
License Type Name: Contributor
License Type Description: Diese Mitarbeiterlizenz ist für professionelle Teammitglieder bestimmt, die keine Entwickler sind, aber aktiv am Projekt beteiligt sind. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Mitarbeiter hat vollen Lese- und Schreibzugriff auf das Änderungsmanagement, auf die Anpassung von Berichten und auf die Planung. Diese Lizenz ermöglicht außerdem den Lesezugriff auf Funktionen des Anforderungsmanagements, des Softwarekonfigurationsmanagements, der Automation (Buildsystem), des Testmanagements und des Designmanagements, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational DOORS Next Generation
License Type ID: com.ibm.team.rtc.contributor
License Type Name: Contributor
License Type Description: Diese Mitarbeiterlizenz ist für professionelle Teammitglieder bestimmt, die keine Entwickler sind, aber aktiv am Projekt beteiligt sind. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Mitarbeiter hat vollen Lese- und Schreibzugriff auf das Änderungsmanagement, auf die Anpassung von Berichten und auf die Planung. Diese Lizenz ermöglicht außerdem den Lesezugriff auf das Softwarekonfigurationsmanagement, auf die Automation (Build-System), auf das Anforderungsmanagement, das Testmanagement und das Designmanagement, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational Team Concert
License Type: 
License Type ID: com.ibm.team.rtc.stakeholder
License Type Name: Stakeholder
License Type Description: Diese Stakeholder-Lizenz ist zur Unterstützung von peripheren Benutzern gedacht, z. B. von externen Kunden, von Mitarbeitern der Benutzerunterstützung oder von Benutzern, die Arbeitselemente modifizieren und den Projektfortschritt beobachten müssen. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Stakeholder hat Lese- und Schreibzugriff auf Change Management sowie Lesezugriff auf Berichte und Planungsfunktionen, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational Team Concert
License Type: 
License Type ID: com.ibm.team.rtc.buildsystem
License Type Name: Build System
License Type Description: Die Clientzugriffslizenz 'Build System' kann nur einer Benutzer-ID zugewiesen werden, die von einem automatisierten Build-System verwendet wird. Damit haben Einheiten des Build-Systems Lesezugriff auf das gesamte Leistungsspektrum sowie Schreibzugriff auf alle Leistungsmerkmale, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational Team Concert
License Type: 
License Type ID: com.ibm.team.rtc.developer
License Type Name: Developer
License Type Description: Diese Lizenz ist für professionelle Entwickler bestimmt, die aktiv am Projekt beteiligt sind. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Entwickler hat vollen Lese- und Schreibzugriff auf das Änderungsmanagement, auf die Anpassung von Berichten, auf die Planung, auf das Softwarekonfigurationsmanagement und auf die Automation (Buildsystem). Diese Lizenz ermöglicht außerdem den Lesezugriff auf das Anforderungsmanagement, das Testmanagement und das Designmanagement, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten.
License Type ProductName: Rational Team Concert
License Type: 
License Type ID: com.ibm.team.clm.contributor
License Type Name: Contributor
License Type Description: Diese Mitarbeiterlizenz ist für professionelle Teammitglieder bestimmt, die keine Entwickler sind, aber aktiv am Projekt beteiligt sind. Ein Benutzer mit zugewiesener Clientzugriffslizenz für Mitarbeiter hat vollen Lese- und Schreibzugriff auf das Änderungsmanagement, auf die Anpassung von Berichten und auf die Planung. Diese Lizenz ermöglicht außerdem den Lesezugriff auf das Softwarekonfigurationsmanagement, auf die Automation (Buildsystem), auf das Anforderungsmanagement, das Testmanagement und das Designmanagement, sofern rollenbasierte Prozessberechtigungen keine diesbezüglichen Einschränkungen beinhalten. Floating-Lizenzen werden dynamisch von einem Lizenzserver zugewiesen. Ein Benutzer mit zugewiesener Floating-Lizenz kann in den Pool der Benutzer aufgenommen werden, die die verfügbaren, auf dem Lizenzserver installierten Floating-Lizenzen gemeinsam nutzen. Führt ein solcher Benutzer eine Operation aus, für die diese Lizenz erforderlich ist, wird ihm vom Lizenzserver dynamisch eine Floating-Clientzugriffslizenz zugewiesen, wenn eine solche verfügbar ist. 
License Type ProductName: Rational solution for Collaborative Lifecycle Management

The license type ID can be used to assign a license to the user.

	IContributor licenseContributor = teamRepository.contributorManager().fetchContributorByUserId(licenseUser, monitor);
	licenseAdminService.assignLicenseWithResult(licenseContributor,	licenseID);

For Example for user “bob” and the license type ID “com.ibm.team.rtc.developer”:

	IContributor licenseContributor = teamRepository.contributorManager().fetchContributorByUserId("bob", monitor);
	licenseAdminService.assignLicenseWithResult(licenseContributor,	"com.ibm.team.rtc.developer");

To remove a license use the code below and provide the license type ID

	IContributor licenseContributor = teamRepository.contributorManager().fetchContributorByUserId(licenseUser, monitor);
	licenseAdminService.assignLicenseWithResult(licenseContributor,	licenseID);

	licenseAdminService.unassignLicense(licenseContributor, licenseID);

Assigning licenses in a batch file

Using a plain java API application is not the only way to assign licenses. It is also possible to use the repo tools to do that. I use the following batch file to assign licenses to the users created for the JKE Banking sample life cycle project that I use to explore CLM.

echo on
set SERVERFOLDER="C:\CLM2016\6.0.3\JazzTeamServer\server"
set REPOSITORY="https://clm.example.com:9443/jts"
set USERID="myadmin"
set PASSWORD="myadmin"


rem primary users
call %SERVERFOLDER%\repotools-jts -createUser userId=bob licenseId=com.ibm.team.rrc.author repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=marco licenseId=com.ibm.rqm.tester repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=marco licenseId=com.ibm.team.rtc.developer repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=deb licenseId=com.ibm.team.rtc.developer repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=tanuj licenseId=com.ibm.rqm.tester repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=rebecca licenseId=com.ibm.team.rtc.developer repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%

rem Build user
call %SERVERFOLDER%\repotools-jts -createUser userId=build licenseId=com.ibm.team.rtc.buildsystem repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%

rem secondary users
call %SERVERFOLDER%\repotools-jts -createUser userId=ursula licenseId=com.ibm.team.rrc.author repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=curtis licenseId=com.ibm.rqm.viewer repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=tammy licenseId=com.ibm.rqm.tester repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
call %SERVERFOLDER%\repotools-jts -createUser userId=sally licenseId=com.ibm.team.rrc.author repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
rem Design Manager License 
rem %SERVERFOLDER%\repotools-jts -createUser userId=al licenseId= repositoryURL=%REPOSITORY% adminUserId=%USERID% adminPassword=%PASSWORD%
pause

This works very well, except that it takes a long time to run since each repotools command has to individually log in.

Download and 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 API that are available in the RTC Server SDK and the RTC Plain Java Client Libraries.

You can download the Eclipse project with the application to print and assign a license to a user here.

You can download the batch file to assign the licenses for the JKE Banking Example in a zip archive here.

Related posts

Summary

The code above can be used to assign and remove licenses from users in RTC and CLM. An alternative method is using the repotools. as always I hope that this helps users out there with their tasks.

Setting Custom Attributes for SCM Versionables

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:

  1. Manage Access Control Permissions for Work Items and Versionables
  2. Setting Access Control Permissions for Work Items
  3. Setting Access Control Permissions for SCM Versionables
  4. 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.

SCM Attributes

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.

Setting Access Control Permissions for SCM Versionables

This is the third post in the series around very fine grained access control permissions for work items and SCM versionables. It explains how to set the access control permissions for RTC SCM versionables.

See the problem description in the first post of the series

Related posts

The posts in this series are:

  1. Manage Access Control Permissions for Work Items and Versionables
  2. Setting Access Control Permissions for Work Items
  3. Setting Access Control Permissions for SCM Versionables – this post
  4. Setting Attributes for SCM Versionables

Also see

Controlling access to source control artifacts in Rational Team Concert

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.

SCM Versionable Access Control

Lets have a look at access control for RTC SCM versionables such as files and folders. The rules have been explained in this post.

Keep in mind, that with RTC version 5.0.2 it is not possible to use access groups to limit access to versionables. The code is prepared for it, but will fail if such an access context is used. So make sure to only use default (which is controlled by the component), project areas, team areas (called process areas if the distinction is unimportant) or a single user as access control context for versionables prior to RTC 6.0.1. The code below reflects the capabilities for 6.0.1 and higher as well.

This image shows the context menu available for selecting the access control context manually. The menu is available from SCM enabled Eclipse views such as package explorer or repository files for files under Jazz SCM version control.

FileAccessControlContextMenu

The next screen shot shows the selections available in RTC 6.0.1 to specify the access control context.

FileAccessControlChoices

  1. Component: This is the default access context, where the component specifies read access
  2. Contributor: SCM elements can be restricted to be accessed by a single user
  3. It is possible to select a project area or a team area as the read access context, only members of that process area (and sub process areas) will have access to the element
  4. Access Group: Select an access group to limit read access to members of that access group

It is important to note, that the access permission does not work for one version if the versionable, but for all elements.

The next section explains how this can be done using Java API code.

SCM Versionable Access Control Code

How to find the objects we are interested in, is explained in this post. The code to manage access contexts for versionables is different from the code used for work items. It does not use an UUID, but a special interface IPermissionContextProvider .

The interface com.ibm.team.scm.common.dto.IPermissionContextProvider is passed to set the context. The interface provides a factory and methods to create the permission context provider.

Default Access Context

The method

IPermissionContextProvider.FACTORY.createClear()

is available to create a default access context (access permission based on access to the component).

Access Contexts for Other Elements

The method

IPermissionContextProvider.FACTORY.create()

is available for item handles of the types IProcessAreaHandle, IAccessGroupHandle and IContributorHandle to create the access context. This example code shows how to get the permission context provider for various items.

IProcessAreaHandle processAreaHandle = ..... get the handle
IAccessGroupHandle accessGroupHandle = ..... get the handle
IContributorHandle contributorHandle = ..... get the handle

IPermissionContextProvider processAreaContext = IPermissionContext
IPermissionContextProvider accessGroupContext = IPermissionContextProvProvider.FACTORY.create(processAreaHandle);ider.FACTORY.create(accessGroupHandle);
IPermissionContextProvider contributorContext = IPermissionContextProvider.FACTORY.create(contributorHandle);
IPermissionContextProvider defaultContext = IPermissionContextProvider.FACTORY.createClear();

Getting the IScmService

To be able to set the permissions for scm versionables, requires the IScmService class com.ibm.team.scm.common.IScmService. It is easy to get this service in the Server API, by basically using

IScmService fScmService = getService(IScmService.class);

In the Client API however, this service is not accessible using the usual call using getClientLibrary() like

IScmService fScmService = (IScmService) teamRepository.getClientLibrary(IScmService.class);

This does not work.

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.

Set Access Control for SCM Versionables

The code to set access control

/**
 * Sets the Access control context for an array of versionable handles
 * 
 * @param vhandles
 * @param component
 * @param contextProvider
 * @param scmService
 * @throws TeamRepositoryException
 */
public static void setControl(IVersionableHandle[] vhandles,
		IComponentHandle component,
		IPermissionContextProvider contextProvider, IScmService scmService)
		throws TeamRepositoryException {
	scmService.setPermissions(vhandles, component, contextProvider, null,
			null);
}

Having a versionable handle, the IScmService, the handle for the component that contains the versionable and the permission context provider, the code to set the permission context looks as follows:

IVersionableHandle versionableHandle = ..... get the handle
IComponentHandle component = ..... get the handle
IAccessGroupHandle accessGroupHandle = ..... get the handle

IPermissionContextProvider accessGroupContext = IPermissionContextProvider.FACTORY.create(accessGroupHandle);

IScmService scmService = (IScmService) ((TeamRepository) teamRepository)
				.getServiceInterface(IScmService.class);

IVersionableHandle[] vhandles = new IVersionableHandle[] { versionableHandle };

scmService.setPermissions(vhandles, component, contextProvider, null,
				null);

If the available data is a change set, the code would look like this

/**
 * Sets the Access control context for the versionable handles on a change
 * set
 * 
 * @param changeSet
 * @param contextProvider
 * @param scmService
 * @throws TeamRepositoryException
 */
@SuppressWarnings("unchecked")
public static void setControl(IChangeSet changeSet,
		IPermissionContextProvider contextProvider, IScmService scmService)
		throws TeamRepositoryException {
	if (changeSet == null) {
		// no change set or no read access to it
		return;
	}
	for (IChange change : (List) changeSet.changes()) {
		if (change.kind() == IChange.DELETE) {
			return;
		}
		IVersionableHandle versionableHandle = change.afterState();
		if (versionableHandle == null) {
			// change was a delete
			return;
		}

		IVersionableHandle[] vhandles = new IVersionableHandle[] { versionableHandle };
		scmService.setPermissions(vhandles, changeSet.getComponent(), contextProvider, null, null);
	}
}

Get Access Control for SCM Versionables

The code below shows how to read the access control context for the versionables. Please note, it is necessary to have read access to the item, to be able to access it at all.

/**
 * @param versionableHandle
 * @param component
 * @param scmService
 * @param message
 * @throws TeamRepositoryException
 */
public static void printAccessControl(IVersionableHandle versionableHandle,
		IComponentHandle component, IScmService scmService, String message)
		throws TeamRepositoryException {

	IVersionableHandle[] vhandles = new IVersionableHandle[] { versionableHandle };
	IVersionablePermissionsReport[] perms = scmService.getPermissions(
			vhandles, component, null);
	System.out.println(message);
	if (perms.length == 0) {
		// no readContext - item is public
		System.out.println("Item is public.");
	} else {
		// readContext already exists, print it
		for (IVersionablePermissionsReport prep : perms) {
			IPermissionContextProvider provider = prep.getContext();
			IAuditableHandle handle = provider.getReadContext();
			System.out.println("Permission context: " + handle.getItemId().getUuidValue());
		}
	}
}

Summary

This post explains setting read access control for SCM versionables. The next post will talk about setting attributes for SCM objects.

Setting Access Control Permissions for Work Items

This is the second post in the series around very fine grained access control permissions for work items and RTC SCM versionables. It explains how to set the access control permissions for work items.

See the problem description in the first post of the series

Related posts

The posts in this series are:

  1. Manage Access Control Permissions for Work Items and Versionables
  2. Setting Access Control Permissions for Work Items – this post
  3. Setting Access Control Permissions for SCM Versionables
  4. Setting Attributes for SCM Versionables

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.

Work Item Access Control Code

Now that we have all the rules and pieces together as explained in this post, lets have a look at the work item access control. Again, note, that work items can only have access groups and project areas set for access control in manual mode as shown in the image below.

WorkItemAccessContextSelection

To set the access context for work items, the interface IWorkItem provides the method

IWorkItem.setContextId(UUID contextId);

It should also be possible to set the internal attribute with the ID “contextId” also available as constant

IWorkItem.CONTEXT_ID_PROPERTY

in the IWorkItem interface.

Working With the UUID Representing the Access Context

How to find the objects we are interested in, is explained in this post.

To be able to set the access control context for work items, it is necessary to understand how to access the value that represents the access context of a process area (project or team area) or access group.

The common API provides this method to access the access context of an item:

com.ibm.team.repository.common.IAuditableHandle.getItemId()

This interface implements (through a number of intermediate interfaces) the interface IItemHandle, which defines the method getItemId() for all items. So strictly speaking the method is available as

com.ibm.team.repository.common.IItemHandle.getItemId()

This means, the access context can be accessed already from the item handle e.g. in case only a handle such as IProcessAreaHandle, IProjectAreaHandle, ITeamAreaHandle, IAccessGroupHandle or IContributorHanlde is available.

It is also available at all resolved IItems such as IProcessArea, IProjectArea, ITeamArea, IAccessGroup or IContributor as all these interfaces implement IItemHandle. In fact it is available on all IItems. Example code:

IProcessAreaHandle paHandle = ..... get the handle
IProcessArea pa = ..... resolve the handle

// These values are the same
UUID paHandleContext1 = paHandle.getItemID(); 
UUID paHandleContext2 = pa.getItemID();

Note, that all items in RTC have an itemID like the one above and can be uniquely be identified by it. Other itemID’s are just not used as access context.

The return value is of the type

com.ibm.team.repository.common.UUID

The UUID is an object that uniquely identifies an item in the repository and can be used to recreate the item as well. The string representation shows up in several places, for example in OSLC links. To get the string representation use

com.ibm.team.repository.common.UUID.getUuidValue()

If it is necessary to recreate an UUID from the string representation as an example named contextIDString, use the method

UUID.valueOf(contextIDString)

This recreates the UUID of the object if the string is a valid string representation of a UUID.

This way, you have the choice to use the UUID or its string representation to set the access context of RTC work items.

Setting the WorkItem Access Context

Given the UUID provided by a project area or access group, it is possible to set the access context of a work item.

Although all the code to retrieve the access context is common code, the code to set the work items context differs on client and server.

In the Client API, use a WorkItemOperation like the code below.

/*******************************************************************************
 * 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 org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.common.UUID;
import com.ibm.team.workitem.client.WorkItemOperation;
import com.ibm.team.workitem.client.WorkItemWorkingCopy;
import com.ibm.team.workitem.common.model.IWorkItem;
import com.ibm.team.workitem.common.model.ItemProfile;

/**
 * WorkItem Operation to set the access context for the work item. This is
 * client code only.
 * 
 */
public class SetAccessControlOperation extends WorkItemOperation {

	private UUID fAccessContext;

	public SetAccessControlOperation(UUID accessContext,
			ItemProfile loadProfile) {
		super("Set Access Context", loadProfile);
		fAccessContext = accessContext;
	}

	@Override
	protected void execute(WorkItemWorkingCopy workingCopy,
			IProgressMonitor monitor) throws TeamRepositoryException {
		workingCopy.getWorkItem().setContextId(fAccessContext);
	}
}

The operation can be called like this:

	SetAccessControlOperation operation = new SetAccessControlOperation(
		UUID.valueOf(context), IWorkItem.FULL_PROFILE);
	operation.run(workItem, monitor);

Because the WorkItemOperation is not available in the server API, a save has to be performed manually like below.

	// Set the work item visibility
	// Get the full state of the parent work item so we can edit it
	// and avoid stale data exceptions
	// Get the required service interfaces
	IWorkItemServer wiServer = getService(IWorkItemServer.class);
	IWorkItem fullItem = (IWorkItem) wiServer
			.getAuditableCommon()
			.resolveAuditable(workItem, IWorkItem.FULL_PROFILE, monitor)
			.getWorkingCopy();

	// Set the context of the work item
	fullItem.setContextId(UUID.valueOf(context));

	// Save the work item
	HashSet additionalParams = new HashSet();
	additionalParams.add("WORK_ITEM_CONTEXT_CHANGE");

	IStatus status = wiServer.saveWorkItem3(fullItem, null, null,
			additionalParams);
	if (!status.isOK()) {
		String parameter[] = new String[1];
			parameter[0] = Integer.toString(fullItem.getId());

		String description = NLS.bind(
				"Failed to save work item ''{0}''.", parameter);
		IReportInfo info = collector.createInfo(
				"WORK_ITEM_CONTEXT_CHANGE"
				+ ": Error running the participant.",
				description);
		info.setSeverity(IProcessReport.ERROR);
		collector.addInfo(info);
		return;
	}

Please note, if this is performed in a participant/follow up action, it is important to send an additional save parameter like “WORK_ITEM_CONTEXT_CHANGE”. This protects the participants from causing a recursion ultimately crashing the server. The participant can protect itself to run again for the save it just performed by testing for the additional save parameter. If the parameter is detected, the participant knows it caused the save and should exit to prevent the recursion.

Please also note, that in some cases you might have a WorkItemWorkingCopy, instead of an IWorkItem. In these cases use a cast or the method getWorkItem() on the working copy to get the IWorkItem item to be able to set the context.

The examples above uses the string version of the UUID, however, it would have been possible to get the UUID directly from the IItem.

Getting the WorkItem Access Context

It is possible to get the access context of a work item, if the work item is accessible for read, by using IWorkItem.getContextId(). The resulting UUID can be used to get the related item.

Summary

This post explains how to set read access control for work items. The next post will explain the details around setting access control for SCM versionables.

Manage Access Control Permissions for Work Items and Versionables

A customer requires very fine grained access control to work items and versionable objects such as files in the SCM system. In addition the customer had the requirement to be able to set attributes on elements in the SCM system.

I knew that it can be set for work items and kind of how to because I had briefly looked at it in the A RTC WorkItem Command Line Version 3.0. But I was not completely sure about the rules and how to access the SCM part and the attributes in SCM.

Since the customer needed this urgently I looked at what the rules are and what can be done.

The content is way too big for just one post, so this is going to be a series. The first post explains the rules around access control permissions and some basic API’s around finding the objects that can be used to provide the access control context.

Related posts

The posts in this series are:

  1. Manage Access Control Permissions for Work Items and Versionables – this post
  2. Setting Access Control Permissions for Work Items
  3. Setting Access Control Permissions for SCM Versionables
  4. Setting Attributes for SCM Versionables

Also see

Controlling access to source control artifacts in Rational Team Concert

License and Download

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.

Problem Description

The first question was, if it was possible to set the permission to access

  1. Work Items
  2. Items in the SCM system such as versionables

The second question was, if it was possible to set the attributes introduced in RTC 5.0 that can be specified and set using the API. The documentation only mentioned the SCM command line.

The third question was, how team areas and access groups can be created automatically.

The forth question was, what exactly the rules are:

  1. Can this be done in the server?
  2. Can this be done in the client?
  3. Can this be done in a command line tool or from another application?
  4. What permissions are required and what are the rules in the different contexts?

Solution Approach

The approach that we chose was to try to implement a minimal demonstrator to demonstrate the capabilities and prove them as a proof of concept. this demonstrator was also intended to serve as a platform to find the rules.

Learning

Here is what we learned creating the demonstrator.

The Rules – Work Items

Work Items have an attribute called “Restricted Access” that can be used to control access to them. There are basically the following modes available for work items that can be used.

  1. Access control using access control of the project area
  2. Restricted access by category
  3. Restricted access by setting the restricted access attribute

Option 1: Only the users that have access to the context set for the project area can access these items. This can be set to everyone basically exposing the work items to everyone. Other options a re project area membership and access control list etc. The rules here are very clear.

Option 2: It is possible to set RTC in a project area to automatically determine access permissions based on the category (filed against) of the work item. This sets the restricted access to the project area or team area associated to the category. Only members of the team area (and members of sub team areas of the team area associated to the category) have access to the work items which are restricted by category. It is worth noting, that a user being associated to the project area can not look into the work items filed against teams, if these limit access, it is quite the opposite.

Option 3: Use a special editor presentation to set the restricted access attribute manually to a project area or an access group. this could potentially be supported by automation.

The most important learning for option 3 is, that it is only possible to set the restricted access attribute to a project area or an access group this way. It is not possible to set the access context to a team area. If the context is set to a team area, it automatically picks up the containing project area. This also holds for automation.

See this help topic on how to set up the work items to allow setting the restricted access.

The Rules – Versionables

Prior to RTC 6.0.1, which has just been released, it is only possible to set read access control to the default (which is controlled by the component) project areas, team areas (called process areas if the distinction is unimportant) and a single user.

If access control is set to a team area, any member of that team area and its sub team areas have access. Note that this is different from option 2 for work items. If access control is set to a project area, any member who has access to the project area has access to the item.

RTC 6.0.1 introduces the capability to set access control to an access group. Only members of this access group have access to the item. This seems to be the best option by far, especially since access groups can contain project areas and team areas which adds their members to the access group.

Please note, that access control applies to the whole item and its history.

JazzAdmin Repository Role

Users with the JazzAdmin repository role have access to any work item or SCM controlled item, regardless of the access control setting. Users with this role (and sufficient licenses) can access all data.

Project Area Administrators

Administrators of a team or project area and don’t have the JazzAdmin repository role can not access items that have access control set to a context they don’t have access to.

General Rules

Users can only set the access context of work items or items in the SCM system to an access context that preserves their access permission. It is not possible to find or select an access group, process area the user has no access to/is member of or a different user and set the access context to it. This would remove the read permissions and is prevented.

Users with the JazzAdmin role and sufficient licenses however can do this, because they don’t loose read access.

General Rules For Automation

All automation can only perform the operations that are permitted to the user that is used to run the automation. This especially means that automation running in the context of a user with JazzAdmin repository role and the required licenses can perform all operations. The user context available in an automation depends on the automation.

  1. Follow up actions (participants) run in the context of the user that is performing the operation on the client or the server. They are especially not elevated run in a JazzAdmin repository role, if the user that performs the operation does not have this role. It is also not possible to use a different users or services to elevate the permissions.
  2. Preconditions (advisors) must not change the triggering elements. Otherwise the same rules apply as described in follow up actions.
  3. Asynchronous tasks or services in RTC are run with JazzAdmin permissions and can use the IImpersonationService to change the operation to a different user context.
  4. Plain Java Client Library or other client based automation run in the context of the user that was used to log into the system.

In the context of this post, 1 means, that it is not possible to set access control in such an operation that would remove read access from the user that performs the operation. If you require rules where this could be necessary, it would be necessary to run in a administrative context such as an Asynchronous task or in a client application with JazzAdmin repository role.

Finding ProcessAreas, Access Groups and Contributors

How to find the access context information needed using the Java API?

Finding ProcessAreas

There are many ways to find ProcessAreas (project areas and team areas) using the API, the simplest one assumes an java.net.URI constructed from a string based name path of the process area separated by ‘/’.

Lets assume a project area named TestProject1 and a team area within the project are named TestTeam1 and a sub team area underneath TestTeam1 named TestSubTeam1.

The URI for the project area could be constructed from the string “TestProject1”. The URI for TestTeam1 could be constructed from the string “TestProject1/TestTeam1”. Similar the URI for TestSubTeam1 could be constructed from the string “TestProject1/TestTeam1/TestSubTeam1”.

Process area names could contain spaces. Spaces are not allowed in URI’s, therefore they need to be replaced by the encoding character string “%20”.

To construct an java.net.URI from a string value use the following code.

String namePath = "TestProject1/TestTeam1/TestSubTeam1";
URI anURI = URI.create(URI.create(namePath.replaceAll(" ", "%20")))

The service to find the process area by its URI is provided by the interface IAuditableCommon. This interface class, as its name implies, is a common interface that is available in the RTC Plain Java API, as well as the RTC Eclipse client and Eclipse server SDK. This allows to use this API call in any possible context, either by

IAuditableCommon auditableCommon = (IAuditableCommon) teamRepository
	.getClientLibrary(IAuditableCommon.class);

in Plain Java and client SDK based code, or using

IAuditableCommon auditableCommon = getService(IAuditableCommon.class);

in the server extensions that all extend AbstractService (or in case of SCM server extensions AbstractScmService, which extends AbstractService).

For code that already retrieved the common Service IWorkItemCommon, for example to find work items, IAuditableCommon is available using the call

IAuditableCommon auditableCommon = workItemCommon.getAuditableCommon();

So the following code would retrieve the access context for the team area “/TestTeam1/TestSubTeam1” nested in the team area “TestTeam1” in the project area “TestProject1”

String namePath = "TestProject1/TestTeam1/TestSubTeam1";
IProcessArea area = auditableCommon.findProcessAreaByURI(URI.create(namePath.replaceAll(" ", "%20")), null, monitor);
UUID context = area.getItemId();

Note, for work items only a project area is a valid context. Setting the context above will result in the project area containing the process area to be set. Alternatively use

UUID context = area.getProjectArea().getItemId();

for work items and document the fact to save the time to figure it out the hard way during testing (like I did).

Finding the Public Access Context

Work items can also be set to public read access. The constant com.ibm.team.repository.common.IContext.PUBLIC is available for that.

UUID publicContext = IContext.PUBLIC.getUuidValue();

provides with the public access context.

Finding Access Groups

Access Groups are managed in the administration pages of the RTC application. It is possible to create, modify and delete access groups. The image below shows this section.

Access Group ManagementAccess Groups are also accessible using the IAuditableCommon common interface that was already used in the section above.

To get all access groups use this code:

IAccessGroup[] groups;
groups = auditableCommon.getAccessGroups(null, Integer.MAX_VALUE,
	monitor);

This returns all access groups up to a maximal number that is passed to the method.

It is possible to pass a filter to select only access groups with specific name pattern like below.

IAccessGroup[] groups;
groups = auditableCommon.getAccessGroups("My*", Integer.MAX_VALUE,
	monitor);

The access groups can be iterated like below to compare the name or do something similar.

for (IAccessGroup group : groups) {
// Compare the value to the access group name.
	if (group.getName().equalsIgnoreCase(value)) {
		return group;
	}
}

Similar to the process areas above, there is also a public access group which can be obtained like this:

return auditableCommon.getAccessGroupForGroupContextId(
	IContext.PUBLIC, monitor);

Finding Contributors

Finding contributors is different in the client and the server. There is no common API available.

In the client API the IContributorManager can be used for example using the following methods.

IContributorManager contributorManager= teamRepository.contributorManager();
// Find a user by the users ID returns a handle
IContributorHandle contributorHandle = contributorManager
	.fetchContributorByUserId(attributeValue, monitor);

// Get all users, returns a list of full IContributor items
List contributors = contManager.fetchAllContributors(monitor);

In the server API the IContributorService is available and provides the following method.

IContributorService contributorService = getService(IContributorService.class);
contributorService.fetchContributorByUserId(userId);

I was not able to locate a way to search for all users like in the client API. The server API usually gets a user passed and there is no need to find all users.

Summary

This post explains the rules around read access control for work items and RTC SCM versionables and some basic API’s around finding the objects that can be used to provide the access control context. The next post will explain the details around setting access control for work items.

Getting the RTC User Work Environment Information

Recently I was asked how to access the users work environment information. This is basically the information displayed in the Work Environment Tab of the user editor.

User Work EnvironmentI was able to get at the Information. The code below shows how that works and what the information means.

Related code on this blog can be found in

Manage Scheduled Absences Using The PlainJava Client Libraries.

Please note, I looked briefly into ways to update that information, but I was not able to find any public interface to do so. I found internal methods that apparently do it, but not in a way that has an easy API provided to the user.

License and Download

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!

You can download the latest version here: as Eclipse project.

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

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 code linked from this post contains Client API.

Solution

The few methods below show how to access the data.

As usual, I use a very simple base class that connects to the repository and only performs the operations needed to get at the data. Please look at the downloadable code, if you are not sure how all that works together.

The specific API for the data in question is in the packages.

 com.ibm.team.apt.common,
 com.ibm.team.apt.client

The run() method below is called with all the parameters needed and basically connects to the team repository. It then finds the user it should look at based on the ID provided.

Next it gets the IResourcePlanningClient client library, and from that the ResourcePlanningManager which provides access to the data we are interested in.

The data we want is stored in the IContributorInfo that is returned by the call to the method getContributorInfo() providing the contributor object for the user we are interested in.

The data of interest is in the IWorkLocationDefinition available from the IContributorInfo. The code gets the information and then evaluates the details to print them.

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

	if (args.length != 4) {
		System.out
				.println("Usage: GetWorkLocationAndWorkDayDetail    ");
		return false;
	}

	String repositoryURI = args[0];
	final String userId = args[1];
	final String password = args[2];
	String userToLookup = args[3];
	IProgressMonitor monitor = new NullProgressMonitor();

	ITeamRepository teamRepository = TeamPlatform
			.getTeamRepositoryService().getTeamRepository(repositoryURI);
	teamRepository
			.registerLoginHandler(new LoginHandler(userId, password));
	teamRepository.login(monitor);
		
	// Get the user to look at
	System.out.println("Data for user: " + userToLookup + ".");
	IContributor inspectUser = teamRepository.contributorManager()
			.fetchContributorByUserId(userToLookup, monitor);
		
	// Get the resource planning client 
	final IResourcePlanningClient resourcePlanning = (IResourcePlanningClient) teamRepository
			.getClientLibrary(IResourcePlanningClient.class);

	// Get the contributor related planning information
	IContributorInfo info = resourcePlanning.getResourcePlanningManager()
			.getContributorInfo(inspectUser, true, monitor);
		
	// Get the worklocation information that contains the working days
	IWorkLocationDefinition location = info.getWorkLocation(inspectUser);
	printWorkLocation(location);
	printWorkDays(location);

	teamRepository.logout();

	return true;
}

First it prints the work location information, basically the user environment information with the timezone and the regional settings.

There is some data “Variant” I am not sure it is used.

/**
 * Print the work location data
 * This includes the available location with timezone
 * 
 * @param location
 */
private static void printWorkLocation(IWorkLocationDefinition location) {
	System.out.println("Location");
	System.out.println("Language: " + location.getLanguage());
	System.out.println("Timezone: " + location.getTimeZone());
	System.out.println("ZoneOffset: " + location.getZoneOffset());
	System.out.println("Country: " + location.getCountry() + " not used");

	// Not used
	System.out.println("Variant: " + location.getVariant() + " not used");
}

Then the code prints the work day information.

/**
 * Print all work days for a users location
 * 
 * @param location
 */
private static void printWorkDays(IWorkLocationDefinition location) {
	System.out.println("\nWorkdays");
	Collection workDays = location.getWorkDays();
	for (IWorkDayDefinition workDay : workDays) {
		printWorkDay(workDay);
	}
}

private static int HOUR_IN_MILLISECONDS=60*60*1000;

/**
 * Print the work day data
 * 
 * @param workDay
 */
private static void printWorkDay(IWorkDayDefinition workDay) {
	int hour = HOUR_IN_MILLISECONDS;
	System.out.println("WorkDay: " + workDay.getDay().getName()
			+ " Literal " + workDay.getDay() + ".");
	System.out
			.println("\tWorking time: " + workDay.getWorkingTime()
					+ " milliseconds equals to " + workDay.getWorkingTime() / hour
					+ " hours");
	System.out.println("\tEndTime " + workDay.getEndTime()
			+ " milliseconds equals to " + workDay.getEndTime() / hour + " hour.");
}

The interesting information here is in the interface IWorkDayDefinition.

  • The day returned by getDay() as IWeekDay which provides the day information using a label and a name; label and name are a string
  • The working time (how many hours a day) for each day using getWorkingTime()
  • The time when the user stops working using getEndTime()

Both time values are provided in milliseconds. The working time is the time in hours set in milliseconds. The end time is the end time in milliseconds from midnight.

Running the code with parameters

"https://clm.example.com:9443/ccm/" "admin" "*****" "curtis"

results in the following output (for the same user shown in the image at the beginning):

Data for user: curtis.
Location
Language: en
Timezone: US/Eastern
ZoneOffset: -18000000
Country: US
Variant: null not used

Workdays
WorkDay: MONDAY Literal MONDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 64800000 milliseconds equals to 18 hour.
WorkDay: TUESDAY Literal TUESDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: WEDNESDAY Literal WEDNESDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: THURSDAY Literal THURSDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: FRIDAY Literal FRIDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: SATURDAY Literal SATURDAY.
	Working time: 0 milliseconds equals to 0 hours
	EndTime 0 milliseconds equals to 0 hour.
WorkDay: SUNDAY Literal SUNDAY.
	Working time: 0 milliseconds equals to 0 hours
	EndTime 0 milliseconds equals to 0 hour.

Summary

This post provides you with all the code and information needed to read and interpret the WorkLocation information stored in RTC.

As always, I hope this post saves users out there some time – or is at least fun to read.

Build Artifacts Publishing and Automated Build Output Management Using the Plain Java Client Libraries

The Jazz Build Engine is unfortunately very limited with respect to publish build results. Can this be done better? Is it possible to automatically move the data of special builds into artifact repositories? I have published some articles in the Jazz.net library  long ago. Since the situation hasn’t really changed, I wanted to publish them here for completeness and to make them easier to find.

The Jazz development uses a similar approach (albeit not that basic) to manage their builds.

See a comparison of binary repository managers.

Publishing Build Output Files

It is possible to upload logs and result files to the build result of a Jazz Build Engine (JBE) build run.

However, uploading big files just makes the repository bigger. Even worse, clicking on any uploaded logs and other uploaded files on a build result leads to downloading the file to the local disk, where the file can hopefully be opened with a local editor.

This does not scale well and ideally it would be nice if all that is in the build result is a link to the build and the supporting result files which one could see in a browser. It would also be interesting to be able to see a web page for each build that shows statistics and result details.

How can this be done easily?

The article Build Artifacts Publishing Using HTTP Servers in Rational Team Concert shows a simple scenario how to do this and have a direct browser-based access to all of the build result files.

As a summary the basic approach used in the article Build Artifacts Publishing Using HTTP Servers in Rational Team Concert is to have the build files, including the built files and the build result information stored somewhere (on a disk) and only publish the URL to that location back to the build result for navigation. The URL is just an index file in the simplest example, it could be far more complex and, for example, contain statistics, test results and test coverage information.

Management of Build Output and Backup or Using Artifact Repositories

Publishing basically means keeping the loaded build repository workspace and the generated files somewhere, and publish them with a HTTP server. No matter how cheap disk space might be, at some point in time you want to get rid of outdated build data that is not referenced any more. You also want to make sure to back up and keep the relevant build data needed to be preserved such as released versions.

The article Automated Build Output Management Using the Plain Java Client Libraries explains how to do this by creating a small RTC Plain Java Client Library application that purges build data and results, allows to back up the relevant builds and to store them in an artifact repository. The example code has a placeholder for this step using IBM Rational Asset Manager. By copying files or using an API this could target any system. Provided the system publishes the data back into the web, the example shows code to add the link to the location in the artifact repository to the build result for later reference.

License and Download

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!

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

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 Build Output Manager

I will not show the whole code here, only some special parts that are interesting. How the code works and more reasoning can be found in the article Automated Build Output Management Using the Plain Java Client Libraries. To run this tool assumes a setup as described in the article Build Artifacts Publishing Using HTTP Servers in Rational Team Concert and the one above.

The code provided is for a more complete version of the Build Output Manager published before, it can actually delete folders and it can be run in a simulation mode. It also creates console output with more information.

The project looks as follows:

Java Project

The folder src contains the single class that makes up this tool.

The folder build contains a jardesc file that can be used to create the Jar file that allows to run it.

The folder BuildPublishing contains an example ant  build script for result publishing and an example for an Apache configuration.

The root folder contains a file RunManager.bat and RunManager.sh that runs the jar file and the class within assuming the jar file is in the same folder. The files define the location for the JAVA_HOME and the location of the Plain Java Client Libraries files. The structure is set up to allow to copy the Jar file and the shell scripts into a sub folder of the installs folder of a Extensions workshop environment and run it. As an example name the folder BuildResultManager. Change the paths if needed.

Folder with JAR file and Scripts

The root folder also contains the file ReadMe – HowToRelease.txt which explains how to build and release the tool. follow the description to release your version.

What the Build Output Manager Does

The general idea is described in the article Automated Build Output Management Using the Plain Java Client Libraries. Here a short summary.

Given a build result root folder that contains sub folders for each build, the Build Output Manager literates the sub folders. For each sub folder it checks if there is a file build.properties available that contains the information needed to identify the build result and the RTC repository.

If there is a build.properties file, the Build Output Manager uses the information inside and contacts the RTC server to check if the build result is still available. If it can find the build result, it checks its details.

It checks if the build result has been marked as a deliverable (also called release) since it last checked. If it is marked as a deliverable, the build is important and needs to be preserved, in order to satisfy the links back from the build result. At this point it would also be interesting to create a backup of the build data and/or move the build data into an artifact repository.

The code here has a stub method addToBackUp() that pretends to store the data in the IBM Rational Asset Manager. This could be enhanced to work for any other artifact repository or backup system. The existing code also shows how to publish the link information to the artifact in the repository back to the build result. For builds identified as deliverable, the code creates a new file in the build result folder that marks this folder as deliverable. This file is used in subsequent runs to skip any checks and thus preserves the folder from deletion.

If the build result is no longer available the Build Output Manager assumes that the build result was purged and the build result folder can be deleted.

If there is no build.properties file, the Build Output Manager can not really determine anything in the repository. However, it can act on aging and other information and has some code built-in the method handleNotQualifyingFolders() to help dealing with this situation and some flags to control its behavior.

By default all non qualifying folders (lacking the build.properties file) are checked for aging. All over a certain age are checked if they should be deleted based on special settings in the Build Output Manager. If the Build Output Manager is set to delete these folders, the deletion is performed.

All non qualifying folders that are past the aging threshold and are not deleted are collected in a list as deletion candidates. After processing all folders, the Build Output Manager publishes a list of notifications for all the remaining candidates for deletion by aging that are left over. This notification provides information in a human readable format that could be used by an administrator to check what is going on.

The information below is the result of a run with the default parameters.

Example output:

Process Build Result ID: _q47SAH2OEeWt7sIN-jhQsg	 in folder: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20151028-1712
	Processing Build Result[UUID _q47SAH2OEeWt7sIN-jhQsg]	 May be deleted	 Personal build	Status:COMPLETED
Process Build Result ID: _wz8NAX2QEeWt7sIN-jhQsg	 in folder: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20151028-1727
	Build result no longer in repository: _wz8NAX2QEeWt7sIN-jhQsg
	DELETING: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20151028-1727
Process Build Result ID: _ZsVi0X2REeWt7sIN-jhQsg	 in folder: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20151028-1731
	Processing Build Result[UUID _ZsVi0X2REeWt7sIN-jhQsg]	 May be deleted	 Personal build	Status:COMPLETED
Process Build Result ID: _QEDkgX2SEeWt7sIN-jhQsg	 in folder: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20151028-1738
	Processing Build Result[UUID _QEDkgX2SEeWt7sIN-jhQsg]	 May be deleted	 Personal build	Status:COMPLETED



Deletion Candidates:
Folder should be deleted: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\C20150429-1043	 age: 183	days. Jazz SCM metadata detected!
Folder should be deleted: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20150407-1128	 age: 205	days. Jazz SCM metadata detected!
Folder should be deleted: C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild\I20150407-1238	 age: 204	days. Jazz SCM metadata detected!

For the folders that contain a build.properties file the Build Output Manager checked if the build result in RTC has been deleted (i.e. while purging results).  For the build folder label I20151028-1727 build result ID _wz8NAX2QEeWt7sIN-jhQsg was identified but the build result could no longer be found in the repository and the folder was deleted (simulation only with default parameters).

The Build Output Manager detected the folder C20150429-1043 that is 183 days old but has no build.properties file. It also detected that the folder contains jazz SCM metadata. This is an indicator that it was created during a repository workspace load operation and is likely to be a build output folder (as opposed to a folder containing cute cat videos).

These folders could have been created by builds that run on a build definition or with build scripts, that don’t create the build.properties file themselves. It might be a good idea to somehow fix this situation. There is a special flags available to deal with situations like this and automatically delete these folders based on age.

If there is no indication of Jazz SCM metadata, this would also be announced. These folders are likely to be folders that have been manually created for other purposes. There is a special flags available to deal with situations like this and automatically delete these folders based on age. However this is an extreme measure and I would suggest to check first if there is not something else going on and make sure the folders in the build output root folder are only created during builds.

RTC Build Result Pruning

RTC has a basic capability to prune build results. The pruner removes unwanted build results from the repository, which ideally drives which build output folders should be deleted. See the article Automated Build Output Management Using the Plain Java Client Libraries for sone more information on that. This capability is very basic. If it seems not be satisfying see Robins blog post about creating a Custom build result pruner that implements a more anhanced strategy. Since this is also based on the Plain Java Client libraies, it would be possible to integrate it with the Build Output Manager discussed in this post.

How to Run the Build Output Manager Tool

The Build Output Manager has the following required parameter

 BuildOutputManager [repositoryURI] [userId] [password] [BuildResultRoot]

The Build Output Manager needs the repository that contains the build results. Currently it will not work with build results that are detected to be in a different repository.

The userID and the password have to be provided and the user has to have the permissions to read and modify the build results.

The Build Output Manager must be run in the context of a user that has permission to read and delete the build output folders.

Here an example for the parameters:

"https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild"

If only these parameters are provided, the tool runs in a default mode. Currently the default mode is internally set to simulation.

The following additional parameters can be added at the end of the parameter list.

  • simulation – the Build Output Manager only simulates operations and does not delete any folders and the result is reported (current default mode)
  • deleteUnreferencedBuildfolders – the Build Output Manager tries to identify build folders that contain the build.properties file; it performs the operations to handle deliverables and deletes the build result folders if they are not a deliverable and a related build result can no longer be found
  • deleteIfSCM – the Build Output Manager performs the operations specified for the mode deleteUnreferencedBuildfolders; in addition all folders that don’t contain a build.properties file but are detected to contain Jazz SCM metadata and exceed the aging limit are deleted
  • forceDelete – the Build Output Manager performs the operations specified for the mode deleteUnreferencedBuildfolders; in addition all folders that don’t contain a build.properties and exceed the aging limit are deleted

Example parameters:

"https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild" simulation
"https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild" deleteUnreferencedBuildfolders
"https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild" deleteIfSCM 
"https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild" forceDelete

An example when calling the RunManager script.

RunManager "https://clm.example.com:9443/ccm/" build build "C:\CLM2014\5.0.2\jazz\buildsystem\buildengine\eclipse\JKEBuild" deleteUnreferencedBuildfolders

You can run the Build Output Manager from chron jobs if it is deployed on the machine running the build engine or containing the build output folders. Another approach would be to use the JBE and have a specific build definition for each engine to run the tool. In any case the tool needs to be run in a user context that has the required permissions to access and delete the files and folders.

Interesting Parts of the Code

Lets look at some of the interesting parts of the code with respect to the RTC Java API. The details can be found in the article Automated Build Output Management Using the Plain Java Client Libraries.

The code below uses the build result ID from the build.properties file to

  1. Create a build result handle
  2. Query the RTC item manager for the resolved build result using the permission aware API
  3. If there is anything the user is denied to retrieve, the code assumes the result is there, but not accessible so a warning is issued and the folder is skipped
  4. If the result is not found the assumption is, that it has been purged and the build output folder is deleted
  5. If the result can be found the folder is preserved and the result is used to check if the build has been changed to a deliverable
private void manageFolders() throws TeamRepositoryException {
	.
	.
	.

		System.out.println("Process Build Result ID: " + buildResultID
				+ "\t in folder: "
				+ aBuildOutputCandidate.getAbsolutePath());
		IBuildResultHandle resultHandle = (IBuildResultHandle) IBuildResult.ITEM_TYPE
				.createItemHandle(UUID.valueOf(buildResultID), null);
		ArrayList handleList = new ArrayList();
		handleList.add(resultHandle);
		IFetchResult fetchResult = aTeamRepository.itemManager()
				.fetchCompleteItemsPermissionAware(handleList,
						IItemManager.REFRESH, null);
		if (fetchResult.hasPermissionDeniedItems()) {
			// can't access but there is a build result
			System.out.println("\t " + buildResultID
					+ " access demied, check permissions!");
			continue;
		}
		if (fetchResult.hasNotFoundItems()) {
			System.out.println("\tBuild result no longer in repository: "
					+ buildResultID);
			checkDeleteFolder(aBuildOutputCandidate);
			continue;
		}
		List retrieved = fetchResult.getRetrievedItems();
		for (Iterator iterator = retrieved.iterator(); iterator.hasNext();) {
			Object result = (Object) iterator.next();
			if (result instanceof IBuildResult) {
				IBuildResult buildResult = (IBuildResult) result;
				processBuildResult(aBuildOutputCandidate, buildResult);
			}
		}
	.
	.
	.

}

The code to process the build result is shown below.

/**
 * Process the build result for additional information that might be useful.
 * For instance check if the Build Result is associated with a deliverable.
 * 
 * @param aBuildOutputCandidate
 * @param buildResult
 * @throws TeamRepositoryException
 */
private void processBuildResult(File aBuildOutputCandidate,
		IBuildResult buildResult) throws TeamRepositoryException {
	System.out.println("\tProcessing Build Result"
			+ buildResult.getItemId()
			+ "\t "
			+ (buildResult.isDeleteAllowed() ? "May be deleted"
					: "Deletion not allowed")
			+ "\t "
			+ (buildResult.isPersonalBuild() ? "Personal Build"
					: "Public Build") + "\tStatus:"
			+ buildResult.getState().toString());
	if (!buildResult.getState().equals(BuildState.COMPLETED)) {
		return; // Only handle completed builds
	}
	IWorkItemCommon workItemCommon = (IWorkItemCommon) aTeamRepository
			.getClientLibrary(IWorkItemCommon.class);
	List deliverables = workItemCommon
			.findDeliverablesByArtifact(buildResult.getItemHandle(),
					IDeliverable.FULL_PROFILE, null);
	if (null != deliverables && !deliverables.isEmpty()) {
		System.out.println("\tDETECTED DELIVERABLE: "
				+ aBuildOutputCandidate.getAbsolutePath()
				+ "\t Mark folder and schedule back up of folder!");
		addToBackUp(aBuildOutputCandidate, buildResult);
		markAsDeliverable(aBuildOutputCandidate);
	}
}

The code below deals with a build that is identified as deliverable and needs to be preserved.

/**
 * Stub for calling a backup operation for a release folder.
 * 
 * @param buildResult
 * @throws TeamRepositoryException
 * 
 */
private void addToBackUp(File aBuildOutputCandidate,
		IBuildResult buildResult) throws TeamRepositoryException {
	if (isMarkedAsDeliverable(aBuildOutputCandidate)) {
		return;
	}
	String theURL = publishToIRAM(aBuildOutputCandidate);
	IBuildResultContribution link = BuildItemFactory
			.createBuildResultContribution();
	// Optional set a category
	// link.setComponentName("Build Output Backup for Audits");
	link.setLabel("Download Artifact from IBM Rational Asset Manager");
	link.setExtendedContributionTypeId(IBuildResultContribution.LINK_EXTENDED_CONTRIBUTION_ID);
	link.setExtendedContributionProperty(
			IBuildResultContribution.PROPERTY_NAME_URL, theURL);
	ITeamBuildClient buildClient = (ITeamBuildClient) aTeamRepository
			.getClientLibrary(ITeamBuildClient.class);
	buildClient.addBuildResultContribution(
			(IBuildResultHandle) buildResult.getItemHandle(), link, null);
}

private String publishToIRAM(File aBuildOutputCandidate) {
	return "http://jazz.net/library";
}

The interesting part of this code is the part that adds a link to the artifact repository on the build result, which allows users to navigate there.

The publishing to an artifact repository in the method publishToIRAM() is not implemented, but it would obviously be possible to add the code required for the artifact repository of your choice. It should return an URL to the published artifact.

Interesting Related Posts

Summary

This example was created a long time ago, but I think it is still of interest. Keep in mind this is by no means production code. You might want to do more testing and enhance it to your needs. As always I hope this helps someone out there to get their job done more efficient.