Issues with the EWM/RTC Extensions workshop in 7.0.x versions

I have seen issues with the RTC Client SDK for the 7.0.x releases recently. The Server SDK seems not to be affected.

Client plug-in development

UPDATE: The issue with the Client SDK has been found and corrected. Just download and use the new Client SDK.

UPDATE: The issue with the server debugging can be solved as explained below.

If you are using the  Rational Team Concert Extensions Workshop for the EWM/RTC versions 7.0.0, 7.0.1, 7.0.2 and try to start an Eclipse client from the client launch as described in section 1.9 Test the RTC Eclipse client launch, you might run into a problem. I reported the issue in Defect 511733 (use your Jazz.net credentials).

This issue has been solved and you should not see it any longer. Make sure to download the latest Client SDK from Jazz.net.

If you need to develop client extensions and run into this problem, check the status of the defect. Worst case, use a 6.0.6.1 SDK to develop your extension. This is absolutely possible if you do not rely on a new client API feature from 7.0.x.

Server debugging

If you are using the  Rational Team Concert Extensions Workshop for the EWM/RTC versions 7.0.2, trying to launch the development server in debug mode that allows to attach an Eclipse debugger to that server, the server startup fails. In ‘1.2__15 start the server using server.startup.bat’ after adding the debug configuration, the server does not start. The log folder only contains the files start.log and console.log. The content indicates that the connection to the debug port failed because the port was already in use. When checking the pot usage, the port is not in use. This has not been seen in any version before. See Defect 527867 for work arounds and solutions.

Update: see http://EWM Extensions Workshop remote debugging in 7.0.x for how to deal with this.

The RTC SDK is about to change in 6.0.3

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

Download the new workshop

Update * the new Extensions Workshop is finished for a while now. it can be found at the original Rational Team Concert Extensions Workshop location.

Why splitting the SDK?

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

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

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

Impact of splitting the SDK

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

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

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

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

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

  • Add a section -vm with an additional line for the java virtual machine to use. If you run Eclipse with a different JVM, e.g. from Oracle, consider to specify a JRE or JDK that is compatible with the one that ships with RTC. This vm would also be used in the workspace setup section.
  • Add -showLocation in the org.eclipse.platform section; this shows the Eclipse workspace path in the upper border of the Eclipse client as below

    eclipse-workspace_2016-11-07_11-23-52

    This makes it possible to actually work with multiple workspaces and knowing which an Eclipse instance is responsible for.

  • A vmargs argument -Duser.language=en to make sure you get a consistent language in the menus if you want.

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

Changes to section: 1.2 Setup for Development

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

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

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

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

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

Changes to section: 1.3 Setup the RTC Tomcat Server

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

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

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

client-server-common

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

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

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

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

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

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

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

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

Other considerations

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

Just Starting With Extending RTC?

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

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

Summary

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

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

Running the RTC Extensions Workshop With RTC 6.0.1

RTC version 6.0.1 is available since end of December 2015. I ran a test to find out if the Rational Team Concert Extensions Workshop still works with RTC 6.0.1. This is what I found.

The version 6.0.1 does not ship Tomcat any more. The Rational Team Concert Extensions Workshop explains how to debug deployed extensions on a Tomcat test server. How does this change the workshop?

Important note: Debugging on Tomcat is only presented as an option, it can be useful if an extension has been fully developed on Jetty, but shows a different behavior on a real environment. Using this technique to develop an extension step by step is not a suggested procedure, instead using Jetty is the preferred way. From this perspective, Section 1.5 in the lab is unimportant for the rest of the workshop and this step could actually be skipped.

Summary

By installing the default values and basically choosing WAS Liberty Profile the workshop works. Basically Tomcat is replaced with WAS Liberty Profile and everything should work as expected. Due to the changes over time, some small adjustments are needed or useful. these adjustments can be found below.

Update

Please see the update for changing the development application server configuration to enable debugging.

Update the issue is fixed: Please note that currently The SDK for RTC6.0.2 has a defect that makes it impossible to be used. See 390811: RTC SDK breaks Extension workshop with missing feature com.ibm.team.rtc.update.site.content.rtc.feature. Use an earlier version of the SDK to develop for now.

Install and Setup Changes

Here some changes that make the workshop more effective. They are described in the workshop in several notes, here a more explicit description.

Section 1.1 Download and Unzip the Required Files from jazz.net

The easiest way to do the Rational Team Concert Extensions Workshop I have found is not to use the Web installer, but to use the ZIP version of RTC.This requires sone minor changes to the sections 1.1. and 1.2 as described below.

You can use the Web Installer, as well as the IBM Installation Manager. If using the Web Installer the changes for 6.0.1 begin in Section 1.3 Setup the RTC Tomcat Server. If using the Installation manager, make sure to install into the folder as described in the workshop.

 1.1__1. Download the product installation files.

In step _b: As alternative, download the ZIP version of RTC named “Jazz Team Server and the CCM Application, and Trial licenses for Rational Team Concert”.

RTC_ZIP Version

Follow the rest of the steps of 1.1_1 and 1.1_2 as described.

If you want to follow the steps from the Rational Team Concert Extensions Workshop and use the web installer, or a the IBM Installation Manager install, make sure to install

 1.1__3. Install the RTC Eclipse client and a test server.

In step _b: To install the zip version of RTC, extract the zip file JTS-CCM-keys-Win64_6.0.1.zip you downloaded for “Jazz Team Server and the CCM Application, and Trial licenses for Rational Team Concert” to the folder:

C:\RTC601Dev\installs\JazzTeamServer

Continue with step _h Unzip the Client for Eclipse IDE zip file

Section 1.3 Setup the RTC Tomcat Server

Instead of Tomcat RTC and CLM 6.0.x bundle WAS Liberty Profile.

 1.1__3. Setup to run the server in debug mode

On windows I have followed the original descriptions in the Extesnsions workshop and added the Java options to the server.startup.bat and it worked for me.

However Lewis Tsao reported in the comments below that on Linux there are changes. He reports the server just dies if he uses suggested lines. He found the article https://jazz.net/wiki/bin/view/Deployment/EnableLibertyRTCServerDebugMode. Based on this, even on Windows it might be worth exploring this and follow the link above. For mode details look at his comments below.

Note that

  • For 6.0.1 the server should be started as “./server.startup -debug” or modify “DEBUG=false” in server.startup to “DEBUG=true”
  • For 6.0.2 the server should be startd as “./server.startup debug”

1.1.__14_b. Open And Review the WorkshopSetup.bat file

The windows version of this file has sometimes problems with some Java versions, because the parameter order is kind of skewed. During development of the tool, this never came up. It will be fixed in a newer version.

Move the parameter -jar in front of the parameter WorkshopSetup.jar

Instead of

Fix workshopSetup.bat_1

the batch file should look like this:

Fix workshopSetup.bat_2

Follow the other suggestions to consider and change the file if needed and perform the rest of the steps as described.

When running the WorkshopSetup command I have very seldom seen errors, one I have seen today was maybe because of the server performance. If this happens, try running the WorkshopSetup again.

Section 1.4 Complete Setup of Your RTC Eclipse Client

For an unknown reason, the project was not initialized. Right click the project in the Team Artifacts view and click initialize to finish the project setup, if this happens.

Section 1.5 Test connecting the Eclipse debugger to Tomcat

If the changes to the server.startup.bat in section 1.3 where successfully performed, this section works the same way with the server deployed on WAS Liberty Profile.

Section 1.6 Test the Jetty Based Server Launch

The software needs more memory. In step

1.6__25__b.

change the memory available for the [RTCExt] Create RTC Test Database launch. The original setting is -Xmx256. With this setting I got a memory error in the JUnit test that creates the development time repository database.

Change the memory setting to -Xmx512 as shown below.

Memory Setting For JUnit launch

Section 1.7 Test the RTC Eclipse Client Launch

In step 1.7.__31.__b.__ii.

The Launch shows a missing bundle.

Eclipse Client launch Missing Bundle

This missing bundle does however not prevent you from running the launch and as far as I can tell at this point in time, the workshop is still working. You can remove the missing bundle as well.

The rest of the workshop should work as desired.

Related Posts

Summary

The  Rational Team Concert Extensions Workshop still works for version RTC 6.0.1. I will however try to find some time to do an overhaul for RTC 6.0.2.

Running the RTC Extensions Workshop With RTC 6.0

I ran a test to find out if the Rational Team Concert Extensions Workshop still works with RTC 6.0 using the RC1 build. This is what I found.

Update:

For RTC 6.0.1 see this post.

Summary

The RTC extensions workshop still runs with RTC 6.0 but you have to increase the memory available for the JUnit test to setup the development time repository database.

Detailed Findings

The workshop worked well, until in step 1.6 Test the Jetty Based Server Launch you create the development time repository database by running the JUnit test Launch.

The original setting is -Xmx256. With this setting I got a memory error in the JUnit test that creates the development time repository database.

Change the memory setting to -Xmx512 as shown below.

Memory Setting For JUnit launch

The second observation I made after successfully running the JUnit test was when I tried to launch the RTC Eclipse client in 1.7 Test the RTC Eclipse Client Launch. The Launch shows a missing bundle.

Eclipse Client launch Missing Bundle

This missing bundle does however not prevent you from running the launch and as far as I can tell at this point in time, the workshop is still working.

Suggestion

Since the memory footprint seems to be increasing at least for the JUnit test, keep this in mind for the other launches. If you run into memory errors, increase the memory settings for your launches. You can find the parameters to consider in the server.startup.bat file.

Additional Information

A user in the Jazz.net Forum pointed out that there is a service error in the server Status summary. You can see it below.

Service Error Test

This error has always been there, as far as I know. I think this is simply a test – the services seem to be just test services to test the error detection capability.

Finally

As always I hope this information helps users of the community in their work.

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

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

The short answer is: Yes!

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

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

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

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

Observations

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

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

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

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

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

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

* Update *

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

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

Summary

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

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

RTC Extension Workshop Overhaul

It took a while, but the Rational Team Concert Extension Workshop overhaul was finally published on Jazz.net.

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.

 What did change?

The new version of the workshop provides

  • Compatibility to newer versions of RTC
  • Compatibility to all RTC and CLM installation types
  • Enhanced, simplified setup
  • Small enhancements of the workshop to address minor changes in the SDK

The Rational Team Concert Extension Workshop is one of the most used workshops in the Jazz.net library. Unfortunately several changes in RTC since its design for RTC 3.0 caused a lot of problems for users. It needed a major change in how the required RTC repository is set up to make it easier to consume.

The main challenge was the set up of the RTC Development repository. The workshop was designed to use TAR database exports created with the repotools to import them and provide the repository as presented below. This repository contains the required development data which is accessible in a repository workspace and a stream with baselines and data.

ExtensionWorkshop Development Repository

This was a lot of manual effort, took time and worse, was not compatible across different versions of RTC. The old files could not be used with newer versions.

As described in this series of posts, the solution was to create the required project, stream and workspace using the Plain Java Client Libraries and upload the required source code to the stream.

The new workshop now uses a small Java Tool WorkshopSetup working with the Plain Java Client Libraries to create the project and to upload the content required to run the workshop. The tool can be downloaded with the Rational Team Concert Extension Workshop.

This allowed to completely remove the steps to import the repository content from the TAR files, which overwrite the repository you set up and rely on a specific setup of the servers done before to avoid conflicts. The removal of the repository exports also reduces the download size considerably.

Since the repository is no longer overwritten, there are no more potential issues with public URI’s and registered applications. It is also no longer necessary to recreate the index files after the import. All these steps where very manual, error prone and time consuming and the workshop is now much more consumable.

The server setup can now use the express setup and is less manual and much faster.

Since the repository is created during the server setup and not overwritten, the evaluation licenses are not expired. There are no license issues anymore. The step to upload the 10Free licenses could be skipped entirely and performed later, once the evaluation licenses expire, if one so desires.

The workshop workbook uses the Web install for RTC as default, but it also describes how to use the Plain ZIP version of RTC. I typically use the latter approach which has some advantages. One of it is, that Installation Manager is not involved and I can safely just delete the files, instead of doing an uninstall. This also works offline or with small bandwidth, if the files are already downloaded.

The WorkshopSetup tool can actually be run against any existing repository and it does not mater which other applications are installed. It should always be able to create the project and upload the content. If you want to start all over with the workshop, it would also be possible to run the WorkshopSetup tool multiple times (e.g. renaming the RTC Extensions Workshop project created for a prior run of the workshop).

The WorkshopSetup tool is started using a batch file or shell script. It will work if you follow the setup instructions. However, you can configure it, if needed. The parameters to configure it are highlighted in the image below.

WorkshopSetupThere are no requirements on the administration user ID anymore, except that it is easier to follow the workshop workbook, if you use the proposed names. If you want to use a different ID, modify the user id and password entries in the workshop setup batch file. All other parameters can also be changed as desired.

Another benefit of the change of the install procedure is that all required data, the source code, licenses, the configuration and debug launch files are now available as exported Eclipse projects. These exports can be used even without having to run the workshop at all. E.g. the launches and configuration files are in the file WorkshopSetup/Data/Configuration/RTCEXTConfiguration.zip and can easily be imported into an Eclipse workspace.

The server launch configurations now contain all the bundles for the licenses that are used in the different ways to package RTC and CLM. Just import the ones from your setup and you are ready to go.

As long as there are no drastic changes to the Plain Java Client Library API the WorkshopSetup tool should work with any version of RTC in the future. It is no longer necessary to start with RTC 4.0 and then to upgrade the repository. I ran the tool with all available RTC 4.x versions up to 4.0.6 and it worked with no problems. The WorkshopSetup tool works also with RTC 3.0.x and it is safe to assume it will also work with upcoming versions of RTC.

* Update * It also works with 5.x.

In addition to these major changes, the launch configurations were tidied up to better map to the newer structures in RTC 4.x and later.

Some feedback from users was also used to make small changes in the labs to make things clearer, easier to follow and address small changes in the API since 4.0 in the text and screenshots.

Starting with Extensions and Automation?

If you just get started with creating extensions or automation for RTC, start with this post Setting up Rational Team Concert for API Development

Summary

A lot of effort went into making the Rational Team Concert Extension Workshop easier to consume and make it compatible to other RTC versions. I hope the result helps users out there to get started with RTC Extensibility and saves some of the precious time. If you have suggestions or run into problems, please provide feedback and questions on Jazz.net in the Forum.

Attribute Customization – Java Based Value Providers, Conditions and Validators

I had to look into how RTC Attribute Customization can be done using Java based Eclipse Extensions. This post shows how this works and provides with examples if you need to get started on the topic.

Update: Also look at A Custom Condition to Make Attributes Required or Read-Only by Role to see more on this kind of extensions.

The Lab 5 talks about using JavaScript for implementing custom providers. It also talks about limitations of the JavaScript API. The current JavaScript API limits you to accessing attributes of the current work items and is also very limited when working with more complex attributes. The JavaScript API in RTC 3.x and 4.x is so limited as it

  • Does not provide means to access extended user information such as team membership or roles
  • Does not allow to access links to Items such as other work items and other work items attributes
  • Does not allow to access information such as subscriptions or attachments

In addition there are few built in providers (see Lab 4 in the workshop) that can be used with list type attributes.

Recently I had to work for a customer request where the built in functionality and the available JavaScript API were clearly not sufficient to match the requirements. This gave me the opportunity to look into extending Attribute Customization using Java based extensions. I thought this would be a nice experience to share.

License and Download

As always, our lawyers reminded me to state, that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license, which basically means you can use it for internal usage, but not sell. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee.

The code presented in this post can be downloaded from here. The code is also available in the RTC Extensions Stream (RTC AttributeCustomization component) in the Jazz In Flight project @ JazzHub. The code shows some simple providers as an entry point and some more complex ones to show the potential.

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 code attached to this post in the development environment you set up in the Rational Team Concert Extensions Workshop and get your own extensions working there as well.

In this context, please also consider to at least read through the Process Enactment Workshop for the Rational solution for Collaborative Lifecycle Management lab 4 and lab 5 to understand how attribute customization works.

I looked into Attribute Customization for the RTC Process Enactment Workshop. You should look into Lab 4 if you don’t know how value providers work and are configured in RTC.

See JavaScript Attribute Customization – Where is the log file? for the log file location for debugging.

The code in this post is common code running in the Eclipse client and the RTC Server.

Finding Information in the SDK

Because I never did this kind of extension before, I started with reviewing the Wiki Article about Attribute Customization on Jazz.net. It is also a good idea to review existing java code to get some ideas.

This section describes how to find example code in the SDK, which is very important to be able to do this kind of work.

The following steps require the development environment to be set up like described in this post. This allows basically to search for references to the extension point and find the code that is involved.

First create a plugin project based on the suggestions in the Wiki Article. Then search for references to the Extension point.

Search for References to an extension point
Search for References to an extension point

The search will find some plugins extending this extension point.

Available extensions
Available extensions

Just double click the plugin com.ibm.workitem.common to open the plugin XML and review the extensions. You can switch to the Extensions tab in the plugin editor and get a better overview. You can navigate to the extending classes by simply looking their name up in the Extension Element Details section, copying the class name and running a Java Search for the declaration for the type. In the search result, find the result related to the SDK and open it in the package explorer.

Type in the search result - Show in Package Explorer
Type in the search result – Show in Package Explorer

Browse the package explorer and explore the SDK source of all the interesting classes. Open classes to look into the code and find out how they work.

Explorer the SDK code
Explore the SDK code

There are some very interesting examples that are worth looking into. Especially the RoleBasedUserProvider and the SecurityContextProvider.

Code to explore
Code to explore

I find the SecurityContextProvider interesting, because I am interested in automation to control the visibility of work items in the context of working with customers. I have a todo created to try to find time to create my own implementation.

Example Implementations

As usual I started with some very simple examples.

  • A default value provider for string type attributes that returns some text
  • A calculated value provider for string and string list type attributes that returns some text
  • A validator for string type attributes that looks if the string contains some sub string and is configurable in the process configuration

These are available out of the box, but as examples easy enough to do without having to fight with more API and I learned a lot from them for reasons I did not expect.

Example Implementations: attributeType

The first decision necessary when following the suggestions in the Wiki Article and creating the extension, is to decide which type the provider should work for. The Article provides a list of examples for the type ID’s, but this is by no means complete. I am not sure yet, where to find the complete list. This section of a Wiki article could be a good starting point. You can look up examples in the extensions mentioned above. Another Theme seems to be to add List in case you want a list type attribute. For example if the return type is string and you want to support a list attribute, the attribute type is stringList.

Also be aware you can and should add several attribute type definitions if you want the extension to support more than one type. String provider are typical in this case. If you want to be able to select them for all string type attributes, define small, medium and large string like below.

ExtensionPointDefinitonsYou can leave out the settings for isDefault and requiresConfiguration in theExtension Elements Details.

API Available in Providers

All provider implementations get called with the following data:

  • IAttribute attribute, the attribute the provider is called for (not available for conditions)
  • IWorkItem workItem, the workitem context the provider is called for
  • IWorkItemCommon workItemCommon, as an entry point to get more API services
  • IConfiguration configuration, the configuration in the process XML related to this provider
  • IProgressMonitor monitor, the progress monitor (can be null)

You can use the workItemCommon to get other common services. Since the providers run in the client as well as in the server the API you have access to seems to be the API common to both. I found IAuditableCommon and IAuditableCommonProcess so far.

Default Value Provider

The code for a default value provider must implement the interface com.ibm.team.workitem.common.internal.attributeValueProviders.IDefaultValueProvider. The type is correctly generated if you follow the Wiki Article. The implementation here is very simple and just returns a string.

The code below shows a very simple default value provider.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IDefaultValueProvider;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

public class SampleStringDefaultProvider implements IDefaultValueProvider {

	public SampleStringDefaultProvider() {
	}

	@Override
	public String getDefaultValue(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {
		return "String Default Value";
	}
}

Calculated Value Provider

The next example is a simple calculated value provider that returns a string containing the time since 1970 in milliseconds. The interface implemented is com.ibm.team.workitem.common.internal.attributeValueProviders.IValueProvider. Please note, all examples below are typed and specify the return type e.g. .

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.Date;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IValueProvider;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

public class SampleStringCalculatedValueProvider implements IValueProvider {

	public SampleStringCalculatedValueProvider() {
	}

	@Override
	public String getValue(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {
		Date date = new Date();
		return "String Calculated Value: "+date.getTime();
	}
}

Again, very basic to show and understand the concept.

A second example is showing a calculated value for a stringList attribute type. The difference is that it returns a List that contains several values.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IValueProvider;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

public class SampleStringListProvider implements IValueProvider {

	public SampleStringListProvider() {
	}

	@Override
	public List getValue(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {
		List result = new ArrayList();
		result.add("Test 1");
		result.add("Test 2");
		result.add("Test 3");
		return result;
	}
}

Validator

The last simple example is a validator that validates if a text field contains a certain sub string. It implements the interface com.ibm.team.workitem.common.internal.attributeValueProviders.IValidator. The validator, configured for a string attribute, by default searches for the search string “Test” in the attribute value and issues a warning.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IValidator;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

/**
 * Validates if a string is contained in the text.
 * 
 * Configure in Process XML
 * 
 * 
 *
 */
public class SampleStringContainsSubstring implements IValidator {

	private static final String SMAPLE_STRING_CONTAINS_SUBSTRING = "com.ibm.js.team.workitem.attribute.customization.providers.SmapleStringContainsTestValidator";
	private static final String REQUIRED_CONTENT = "requiredContent";
	private static final String WARNING_LEVEL = "warning";
	private static final String SEVERITY = "severity";
	private static final String VALIDATION_OK_STATUS = "ValidationOK";
	private static final String CONFIGURATION = "configuration";

	private String fSearchString;
	private int fValidationSeverity;

	public SampleStringContainsSubstring() {
	}

	@Override
	public IStatus validate(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {
		getConfiguration(configuration);

		String value = (String) attribute.getValue(workItemCommon.getAuditableCommon(), workItem, monitor);
		if(value.indexOf(fSearchString)>=0){
			return new Status(Status.OK, SMAPLE_STRING_CONTAINS_SUBSTRING,VALIDATION_OK_STATUS);
		}
		return new Status(fValidationSeverity, SMAPLE_STRING_CONTAINS_SUBSTRING, "Validation: String must contain '"+fSearchString+"'");
	}

	private void getConfiguration(IConfiguration configuration) {
		fSearchString = "Test";
		fValidationSeverity=Status.WARNING;
		IConfiguration parameters= configuration.getChild(CONFIGURATION);
		if(null!=parameters){ // We got a configuration
			String customSearchString=parameters.getString(REQUIRED_CONTENT);
			if(null!=customSearchString)
				fSearchString=customSearchString;
			String configuredValidationSeverity=parameters.getString(SEVERITY);
			if(null!=configuredValidationSeverity)
				fValidationSeverity =  configuredValidationSeverity.equalsIgnoreCase(WARNING_LEVEL)?Status.WARNING:Status.ERROR;
		}
	}
}

The code is a bit more complex, because it allows to configure the test string and the severity in the process XML. The configuration and defaults are read in getConfiguration() and stored in fields. Then the attribute value is read and tested if it contains the substring. If not, a message is created that shows in the UI. Based on the configuration the severity is of level error or warning. Error would allow to prevent saving a work item together with the Attribute Validation work item save precondition. The configuration would look like this:

Validator configuration in the process XML
Validator configuration in the process XML

Condition

I could not come up with an easy condition. Instead I looked into more complex things next. The next examples I did, were focused to automate something based on the role of a user.

The following condition provides information, if the user has a set of roles in the process area the workitem is owned by. It can for instance be used to make attributes mandatory or read only based on this information. The condition is fully configurable in the process XML and can manage one or more roles.

Please be aware that the extension point schema has an issue. If you create the class to handle the extension, you get an error. Create it manually or fix it. The class you create should implement com.ibm.team.workitem.common.internal.attributeValueProviders.ICondition.

Please see the code blow for details.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.IContributorHandle;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.ICondition;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.model.IWorkItem;

/**
 * Condition that checks if the user editing the work item has a specific role
 * 
 * Configure in Process XML
 * 
 * 
 * 
 *
 */
public class SampleCurrentUserHasRoleCondition implements ICondition {

	/* (non-Javadoc)
	 * @see com.ibm.team.workitem.common.internal.attributeValueProviders.ICondition#matches(com.ibm.team.workitem.common.model.IWorkItem, com.ibm.team.workitem.common.IWorkItemCommon, com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration, org.eclipse.core.runtime.IProgressMonitor)
	 * 
	 * Return true if the user has the specified role, else false
	 */
	@Override
	public boolean matches(IWorkItem workItem, IWorkItemCommon workItemCommon,
			IConfiguration configuration, IProgressMonitor monitor)
			throws TeamRepositoryException {
		List lookupRoles = ContributorUtil.getConfiguration(configuration);
		IContributorHandle user= workItemCommon.getAuditableCommon().getUser();
		return ContributorUtil.hasRole(workItem, user, lookupRoles, workItemCommon, monitor);
	}
}

That is short. The reason is, that all the code is in the class ContributorUtil. I was able to reuse that code in several ways and ended up collecting it in the utility class. The method getConfiguration() basically gets the roles to look for from the process configuration.

Then the code gets the IContributorHandle of the current user and the method hasRole check if the user has the role.

The code for the ContributorUtil is below.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.process.common.IProcessArea;
import com.ibm.team.process.common.IProcessAreaHandle;
import com.ibm.team.process.common.IRole;
import com.ibm.team.repository.common.IContributor;
import com.ibm.team.repository.common.IContributorHandle;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IAuditableCommonProcess;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.model.IWorkItem;
import com.ibm.team.workitem.common.model.ItemProfile;

/**
 * Utility class to provide contributor related utilities
 *
 */
public class ContributorUtil {

	private static final String DEFAULT_ROLE_TEAM_MEMBER = "ScrumMaster";
	static final String ROLE = "role";
	static final String PROCESSAREA = "processArea";

	/**
	 * Returns a list of members that have a certain role in the process area a work item is filed against
	 * 
	 * @param workItem
	 * @param lookupRoles
	 * @param workItemCommon
	 * @param monitor
	 * @return a list of contributor handles
	 * @throws TeamRepositoryException
	 */
	public static List findProcessAreaMembersByRole(IWorkItem workItem, Collection lookupRoles,
			IWorkItemCommon workItemCommon, IProgressMonitor monitor)
			throws TeamRepositoryException {
		IProcessAreaHandle processAreaHandle = workItemCommon.findProcessArea(workItem, monitor);
		IProcessArea processArea = (IProcessArea) workItemCommon.getAuditableCommon().resolveAuditable(processAreaHandle,
				ItemProfile.PROCESS_AREA_DEFAULT,monitor);
		IAuditableCommonProcess auditableCommonProcess= workItemCommon.getAuditableCommon().getProcess(processArea, monitor);
		IContributorHandle[] userhandles = auditableCommonProcess.getContributorsWithRole(processArea.getMembers(), processArea, lookupRoles.toArray(new String[lookupRoles.size()]), monitor);
		return workItemCommon.getAuditableCommon().resolveAuditables(Arrays.asList(userhandles), ItemProfile.CONTRIBUTOR_DEFAULT, monitor);
	}

	/**
	 * Returns true if the user working on the work item has a specified role in the process area 
	 * the work item is filed against
         *
	 * @param workItem
	 * @param user
	 * @param lookupRoles
	 * @param workItemCommon
	 * @param monitor
	 * @return true if the user has the specified role, else false
	 * @throws TeamRepositoryException
	 */
	public static boolean hasRole(IWorkItem workItem, IContributorHandle user, List lookupRoles,
			IWorkItemCommon workItemCommon, IProgressMonitor monitor)
			throws TeamRepositoryException {
		IProcessAreaHandle processAreaHandle = workItemCommon.findProcessArea(workItem, monitor);
		IProcessArea processArea = (IProcessArea) workItemCommon.getAuditableCommon().resolveAuditable(processAreaHandle,
				ItemProfile.PROCESS_AREA_DEFAULT,
				monitor);
		IAuditableCommonProcess auditableCommonProcess= workItemCommon.getAuditableCommon().getProcess(processArea, monitor);
		Collection roles = auditableCommonProcess.getContributorRoles(user, processArea, monitor);
		for (IRole aRole : roles) {
			if(lookupRoles.contains(aRole.getId())){
				return true;
			}
		}
		return false;
	}

	/**
	 * Reads the role configuration
	 * 
	 * Configure in Process XML
	 * 
	 * 
	 * 
	 * 
	 * @param configuration
	 * @return
	 */
	public static List getConfiguration(IConfiguration configuration) {
		ArrayListlookupRoles=new ArrayList();

		List processAreaConfigurations= configuration.getChildren(PROCESSAREA);
		if(null!=processAreaConfigurations&&!processAreaConfigurations.isEmpty()){ // We got a configuration
			for (IConfiguration roleConfiguration : processAreaConfigurations) {
				String foundRole=roleConfiguration.getString(ROLE);
				if(foundRole!=null){
					lookupRoles.add(foundRole);
				}
			}
		} else {
			lookupRoles.add(DEFAULT_ROLE_TEAM_MEMBER);
		}
		return lookupRoles;
	}
}

The method ContributorUtil.hasRole() basically gets the process area and then gets the roles of the user in this process area and then checks if one of the roles matches a configured role.

ContributorUtil.getConfiguration() basically reads the process XML configured for the extension and returns a list of roles configured. By default and unconfigured it looks for Team Member. Please be aware it looks for the role ID and not the display name.

Value Set Provider

As an example for a value set provider that implements com.ibm.team.workitem.common.internal.attributeValueProviders.IValueSetProvider see the example that provides a set of users with roles. The code looks as shown below:

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.IContributor;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IValueSetProvider;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

/**
 * This ValueSet Provider returns a list of users that have the configured role 
 * in the process area the work item is filed against
 * 
 * Configure in Process XML
 * 
 *   
 * 
 *
 */
public class SampleUsersWithRoleValueSetProvider implements IValueSetProvider {

	@Override
	public List<? extends IContributor> getValueSet(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {
		List lookupRoles = ContributorUtil.getConfiguration(configuration);
		return ContributorUtil.findProcessAreaMembersByRole(workItem, lookupRoles,
				workItemCommon, monitor);
	}
}

It uses the same methods provided by the ContributorUtil class used by the other more complex providers and conditions.

It works for contributor as well as contributorList attribute types.

Additional Providers

ContributorUtil.findProcessAreaMembersByRole() basically finds the users that have a role matching the list of roles in the process area and returns the users as list. I used this in several other providers.

  • Sample User With Role In ProcessArea Default provides a default value for one user with matching roles (the first of the returned users) for a user type attributes
  • Sample User With Role In ProcessArea Default provides a default value for all users with matching roles  for a userList type attributes
  • Sample User With Role In ProcessArea Calculated Value returns the first user in the list of found users with one of the roles back as calculated value for user type attributes
  • Sample Users With Role In ProcessArea Calculated Value returns all matching users found for userList attribute types
  • Sample Users With Role In ProcessArea provides users with matching roles

The image below shows the classes that implement the required interfaces.

Additional Providers for users with roles
Additional Providers for users with roles

All the provider classes look very similar. They implement one or more interfaces and use the utility class to get the required data. Here an example:

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2013. 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.team.workitem.attribute.customization.providers;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.IContributor;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IDefaultValueProvider;
import com.ibm.team.workitem.common.internal.attributeValueProviders.IValueProvider;
import com.ibm.team.workitem.common.model.IAttribute;
import com.ibm.team.workitem.common.model.IWorkItem;

/**
 * Implements a value provider that returns the users that have a specific role in the process
 * area the work item is filed against.
 * 
 * Configure in Process XML
 * 
 * 
 * 
 * 
 *
 */
public class SampleUserWithRoleValueProvider implements IDefaultValueProvider,IValueProvider {

	public SampleUserWithRoleValueProvider() {
	}

	@Override
	public IContributor getValue(IAttribute attribute, IWorkItem workItem,
			IWorkItemCommon workItemCommon, IConfiguration configuration,
			IProgressMonitor monitor) throws TeamRepositoryException {

		List lookupRoles = ContributorUtil.getConfiguration(configuration);
		List users = ContributorUtil.findProcessAreaMembersByRole(workItem, lookupRoles,
				workItemCommon, monitor);
		if(!users.isEmpty()){
			return users.get(0);
		}
		return null;
	}

	@Override
	public IContributor getDefaultValue(IAttribute attribute,
			IWorkItem workItem, IWorkItemCommon workItemCommon,
			IConfiguration configuration, IProgressMonitor monitor)
			throws TeamRepositoryException {

		return getValue(attribute, workItem, workItemCommon, configuration, monitor);
	}
}

All these providers can be configured for one or more roles in the process XML like shown below. The configuration is within the entry for the provider as described in the Jazz.net Wiki entry about attribute customization.

Provider configured with two roles
Provider configured with two roles

Deploying

I ran this in a test environment set up as described here.

The downloadable code contains a feature and an update site project. Follow the Rational Team Concert Extension Workshop and the instructios in the Wiki Article about Attribute Customization to deploy the code on the client and the server.

Related Posts

Summary

The code above is a good starting point if you want to create your own providers. There are more capabilities that you can use with Java compared to JavaScript. What data really is accessible remains to be seen. I still have to look if it would be possible to for example access SCM components and the like. I hope it is work reading and helps some users out there to save some time to get started with this topic.