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.

Adding custom commands to the SCMUtils

The SCMUtils is based on a framework that I developed over time. The framework provides easy to reuse mechanisms to create custom commands that handle most of the essential requirements automatically. It handles calling a command based on a name string, the parameters the command needs and optional parameters. The command can define its own help content that is printed when either the command was called with missing parameters or if the command name is not supported. This blog post explains the steps needed.

What are the SCMUtils?

Please see SCM Utils – SCM data secure sharing, statistics and more for what they are and how to get them.

Enhancing the tool with own commands

It is easy to implement your own commands. The framework project provides abstract classes that can be used to implement own commands.

The framework allows easy implementation of new custom commands.

The class SampleCommandCmd is a simple example that can be used as a starting point. It implements all the basic capabilities that are needed.

The class AbstractCommand can be extended to a simple command that can execute your own code.

The class AbstractTeamrepositoryCommand is an abstract class that can be used to implement custom commands that interact with a Jazz application. It manages the parameter and behavior required for connecting to a Jazz server. In addition it automatically implements scenario logging. It can be extended to implement commands that work against a Jazz server.

It is not necessary to use one of the classes above. It is only required to implement the interface ICommand.

Tips and tricks for implementing custom commands

The framework comes with a sample command, that you can look to understand how the implementation works. If you want to create your own command, you should not do that in the project com.ibm.js.team.supporttools.framework. You should add it in a project area that refers to the com.ibm.js.team.supporttools.framework project. E.g. you can add the command in the project com.ibm.js.team.supporttools.scmutils.

Open the command /com.ibm.js.team.supporttools.framework.SampleCommandCmd and study the class.

Sample class part 1

The class SampleCommandCmd extends AbstractCommand, so it does not inherit logging into a jazz server. It also implements ICommand (which it inherits from AbstractCommand).

The next part is to define a logger. The framework uses Simple Logging Facade for Java (SLF4J) to provide logging. The log file will be written to disc. Use the logger to add custom logging.

The command must implement the default constructor and pass the command id to the framework. The super class implements this, so the command name is passed to the super class.

In addCommandOptions(), the class adds additional options (parameters). The first parameter in addOption() is the option/parameter name, the second defines if the option requires a value. The third parameter is the description of the option.

Sample class part 2

The command has to make sure it gets the options it needs. This is checked in the next step. The method checkParameters() is used to do just this. Test if the required options are available.

The method printSyntax() is called if there is some kind of issue with calling the SCMUtils. Implement your documentation here. The logger by default prints log level info.

Sample class part 3

The entry point for the custom code is the execute() method. This usually gets all the mandatory options and their values. The method getCmd().getOptionValue() is used to get the parameter or option value if the option has a value. The method getCmd().hasOption() is usually if the option does not have a value and is more like a flag.

Then it usually executes the payload code that does whatever the command is supposed to do. The return value should be true if the command succeeded and false otherwise.

Adding the custom command to the CommandFactory

After implementing a new command, it has to be added to the ScmSupportToolsFactory in the project com.ibm.js.team.supporttools.scmutils to make it available to be called..

The command factory

This is where the command needs to be added. See the available commands.

Add a command

Remove the comments before the put(new SampleCommandCmd()), to enable the sample command. You would add a put for your own command here. The SampleCommand is a good learning execise if you want to learn debugging.

Summary

It is really simple to add new commands, there is a set of commands already available, copy one of those if it looks similar to what you want to do.

Like always, I hope this helps someone out there.

Learning To Fly: Getting Started with the RTC Java API’s

I intend this to become the beginners guide for the RTC java API’s. The reason is, I spend far too much time on the forums trying to answer beginner questions on how to get started over and over again. I intend this post to be my link to answer these questions without having to repeat everything all over.

Where to Start?

You first have to understand what API’s are available and what you can extend. If you don’t understand these basics, you can’t decide on how to proceed. It is also a good idea to understand RTC Process Customization and what you can and cannot do.

For more examples have a look at the Jazz Community. If you continue, consider also contributing there.

Setting up Your Development Environment

If you determined you are interested in one of the Java API’s, you need to set up your environment for Java API development. It is extremely important to perform the steps in that post to have an environment, that has the RTC SDK installed as well as the Plain Java Client Libraries. Do the whole workshop even if you just want to use the Plain Java Client Libraries to code up some automation. This familiarizes you with the concepts of plug-ins and give you some first glimpse on the API.

Even if you intent to develop only Plain Java Client Libraries, you should use a plug-in project to develop your code, because that allows to trick the Eclipse Plugin Development Environment (PDE) into showing you the whole source code of the RTC SDK. It requires to set up your environment as explained in Setting up Rational Team Concert for API Development. This requires to run at least the client parts of Lab 1 of the Rational Team Concert Extensions Workshop.

As a benefit this allows you to

  • See the java doc, comments on interfaces, classes and on methods
  • See the code of huge parts of the Plain Java Client Libraries and the RTC SDK
  • Search interfaces, classes and methods even with using an asterisk if you are not sure about the names and packages
  • Search for references to interfaces, classes, methods, extension points to go looking for inspiration and example code

Search The APIGetting started with the RTC Plain Java Client Libraries

To understand how that works read the post Understanding and Using the RTC Java Client API. Especially read the sections

  • Getting Started With Developing for the Plain Java Client Libraries
  • Debugging Client Code and Finding Information about the API
  • Prepare Your Project to Allow Debugging
  • Finding Information About the API

You should carefully read the whole post Understanding and Using the RTC Java Client API, as it explains how the basic mechanisms in the API work. This is also interesting if you intent to write server extensions.

Getting started with Eclipse Client and Server Extensions

If you are not (yet) interested in the content of this section, skip the rest of this section and go to “Where can I find Examples and Example Code?“.

The best place to start is following the Rational Team Concert Extensions Workshop. This provides you with a fully set up environment for debugging and guides you through all the important steps that are necessary to develop client and server extensions. You might also want to look at Bartosz Chrabskis post How to create Rational Team Concert – Advisor & Participant Extension (step by step) and the related video for creating a participant and the video for creating an advisor.

RTC provides a lot of ways to extend the Eclipse based clients and the server. The most important in general are

  • Pre-conditions which are also referred to as Advisors, because they drive the process advisor behavior of operations
  • Follow-up action which are also referred to as participants, because they participate in the process behavior of operations
  • Attribute Customization which are also referred to as providers, because most of them provide values for work item attributes; please  find examples here
  • Components which are used to group extensions

The wiki topic Team Process Developer Guide provides a great overview about what you can do and what the rules are.

On the RTC Server side it is also possible to create asynchronous tasks, that can perform operations such as event generation and mail notification. An example with code and explanation can be found in the post Due Date Notifier – an Asynchronous Task Example.

There are additional extension points available on the client and on the server that can be used. Some examples are

  • Eclipse Client UI Extension points
  • RTC Web UI Extension points

There are still more, that I haven’t even looked at yet.

The most important part is to be able to develop and debug your server extensions using Jetty as explained in the Setting up Rational Team Concert for API Development. If you can’t do that, it is just a waste of time and I would consider not trying it out at all. You also always want to have a dedicated server for extensions development, deployment testing and functional testing.

The code used in advisors and participants is very similar except that the interface used is different and the result that is returned is also different.

Advisors and participants always run in the context of the user that calls the operation. This means they can only access data the user is able to access and perform operations the user is permitted to.

In advisors it is not permitted to modify the element for which the advisor is triggered. In participants this is allowed.

Participants that modify or create elements have to perform an additional save for the objects modified. Please note that this can trigger the same or another participant to be executed. This can result in a server crash, if it causes a recursive descent for a recursion that does not stop. To prevent that, it is possible to pass additional arguments in the save that the sub-sequentially called  participant can use to prevent running into a recursion. See for example this post for how that can be used.

The Extension Points and Operation ID’s to assign advisors and participants to the specific operation to work for can be found here.

In general it is the best approach to extend the RTC Server if at all possible. The reason is that this makes deployment easier. Deployment basically has to only happen on the server and deploying on all the clients can be avoided.

Deploying Extensions

If, and only if, your extension works in the Jetty based development and debug environment, you can deploy it on a real server. If you have not successfully tried your extension on Jetty as explained in the Rational Team Concert Extensions Workshop, it does not make any sense to try deploying it on a test server, let alone on a production server.

The Rational Team Concert Extensions Workshop handles deploying extensions very manual. The post A Custom Condition to Make Attributes Required or Read-Only by Role explains how this can be made more automatic in the section Deploying the Extension.

If the extension works on Jetty, the worst that can go wrong deploying it on a real server is that the dependencies in the extension include libraries that are not available on the server.

Other issues could be missing or not satisfiable dependencies, version issues, missing provision profiles or typos in the profile or corrupt files. This would show in the log file during server start up. Check the RTC Server log (i.e. server/logs/ccm.log).

Please note, a deployment error, a typo in the provision profile or missing or corrupted files in the sites folder can lead to the server crashing / not successfully starting up. The server start up can be interrupted and the server may not be reachable. See the server log for hints what might be the problem.

Please refer to the post Is The Extension Deployed? How Can I Redeploy? for checking if the deployment actually worked and for maintaining and upgrading server extensions.

Client extensions are required if the data that it works with is only available on the client, or if the extension is needed on client and server anyway e.g. for Java based attribute customization provider.

REST APIs

As explained in What API’s are available and what you can extend. There are REST APIS available.

See the Jazz API Landing page for which APIs are available.

These APIS require a HTTP Client to communicate with the server. These APIs can be used from within the plain Java Client Libraries or using other tools. The blog Registering Custom Resource Intensive Scenarios to CLM Applications shows several examples.

Check Using a REST client to authenticate to ELM/CLM Applications and  Give Me A REST for how to get started.

Where can I find Examples and Example Code?

There are countless examples out there, here on Jazz.net, on Stackoverflow and on many other blogs and sites. But apparently this is not enough or too hard to find. So I will try to put guidance on how to get started here.

The SDK

As already explained you can search for code that ships with the RTC SDK. This requires a working development environment as described above and here.

This Blog

You can find examples and example code in this blog. The easiest way to do so is to search the blog. This is really easy. Type the interface, method or any other clue you search for in the search window on the top right section underneath the banner and then use the “Search” button.

Search the BlogThen go through the list of posts that appear.

Most posts have working code attached for download as well.

There is also a page with Interesting Links that I maintain and add stuff that I come across. There are many links to examples for API and other interesting sources.

The Internet

We live in the times of search engines. In the past, like 25 years ago, you had to go to a public library and try to find relevant information or books that most likely were not there. Today you can use your preferred search engine and, with very few effort, find all you can ask for.  It is of course always easier to ask someone else to “Google that for me”, but it is way better to skill up to do it yourself in these Darwin times.

A good approach in this case is to just come up with some keywords, interface or class name and run the search engine on it. In my experience some words what you are looking for and RTC usually is enough. I find the interesting information usually on the first two pages. If not, I try to change and refine my query. Examples for typical search paattern are

  • “create work item java API RTC”
  • “access work item attribute java API RTC”
  • “RTC API IIteration”

If the results on page one are just too many and not promising it is possible – for Google at least – to limit the scope of the search to specific sites.

Using Search EnginesAn example for this pattern would be

  • “create work item java API RTC site:jazz.net”

This is most useful if you know that there has to be something there or recall something was there and you can’t remember where. I find this even more effective than using the search engine available on Jazz.net, because it usually shows the information I am looking for higher in the ranking.

Good sites are

Additional references

Summary

If you want to get started with the RTC Java API’s, work through this blog post and the resources linked to it. I will try to extend this post with more detailed links for specific topics in the future.

As always I hope that helps users out there.

Give Me A REST

Recently I worked with OSLC/REST and discovered a nice REST client that I find really useful. I thought I would share it with you here.

If you have found tools that help you with this and want to share, please comment to the post. Please use English, describe the tool, what it does and why it is useful. If possible provide the URL in the comment as well. This will help me distinguishing the valuable information from occasional spam that slips through.

* Update * See Postman as another alternative. Links can be found below.

I have actually not done that much work with OSLC/REST in the past. I worked with the Java API’s most of the time. I have however done the Open Services for Lifecycle Collaboration Workshop in the past and also helped submitting it in classes.

The workshop suggests to use Firefox and one of the REST Client Addons available. I did exactly that and it was a pain in the, err.., neck. Why? The whole URL was maintained in one line and that, every time I changed the focus, snapped back to the position in the front. I found myself frantically scrolling back and forth trying to find the last edit location. In general the display did not give me a good way to understand what the request did and if there were issues with it. Not pretty. I tried out alternatives, but I couldn’t find anything satisfying.

I decided to try a different browser – despite the fact that I really like Firefox.

I looked into Chrome, which I recently started to use for JavaScript based Attribute Customization as described in this Wiki page and the Process Enactment Workshop (Lab 5). It suits me way better for JavaScript debugging, as I find it a lot easier to find the script, compared to Firefox Firebug.

The Nugget – Advanced REST Client

I discovered the Advanced REST client. And I it’s a nugget. A really big one actually, I think. You can simply download and install it in Chrome and have it in your Apps tile in the bookmarks bar.

AppBookMarksThis makes it easy to reach and does not take away a lot of real estate.

Now what are the things that distinguish this from other REST tools I have seen so far?

URL Management

The URL management is really nice as it basically allows you to work in two modes.

There is the traditional mode where you have the whole URL in the URL field. This is most efficient to use if one has a complete URL available and wants to copy/paste it.

Traditional URL ManagementThe first real great difference however is the small triangle in front of the URL field. It allows you to automatically decompose the URL into its interesting parts with respect to REST and also to easily manage the query parameters.

Note, I found some URL’s where this does not work as expected for the decomposition. You can still use the feature, but folding/unfolding needs some manual work during unfolding. I hope this gets corrected soon.

Decomposed URLThis is very useful, as it allows to focus on the parts that are really interesting and removes the need to parse the URL visually. It is really easy to edit, add and remove query parameters to create the needed content.

There are also several ways to help with encoding and decoding the request data.

The same is available for the request headers.

Request HeaderIt is possible to use the Raw mode to copy and paste complete headers and it is possible to switch to a Form view like above that works similar to the query parameter section.

 Manage Projects And Save Requests

The second really useful feature is the ability to manage requests and to save them in projects. This allows to store requests that work or are under construction for later use.

Manage And Save RequestsWhile I was looking into OSLC, I had issues with my request several times and I found myself maintaining my URL’s in a text file while I was exploring. Being able to save the request makes it a lot easier and it is no longer necessary to switch between applications.

If something works, it can be kept and changed to work towards the final goal.

You can have multiple projects to manage the request, for example for different projects.

Other REST Tools

I found another REST tool that has similar capabilities.

Postman is available as application (online usage) and as Packaged App. It provides similar capabilities, except I miss the encoding/decoding option. The advantage of Postman is that it keeps a request history. This is easier to use compared to saving the change every time.

Summary

The Advanced REST client together with Chrome made my life a lot easier and I can only recommend to use it. If you do, give it a big thumbs up and donate to help supporting it.

As always I hope this is useful to the Rational Team Concert and CLM users out there.

Using RTC to Work with DevOps Services and With Bluemix

I recently had a look into Bluemix and how to use it with Eclipse to develop cloud applications. The blog post also mentions that there is an integration to DevOps Services that enables to use work items for planning. It also allows to use GIT or Jazz SCM to manage the source code.

Recently I had a look into how that works and I would like to share here what I learned. This post assumes you have performed the first steps to setup your environment following the Getting started With Bluemix post already.

Please note: DevOps Services as well as Bluemix are evolving quickly, adopting for new needs as they arise and what is described here might not be the only possible solution or outdated if you look at it later. It might be a good idea to check with the current documentation of DevOps Services.

Creating a new DevOps Services Project

The first step to get started with DevOps Services, is to create a new project to manage work items and the source code.

After signing into DevOps Services, using the IBM ID created for Bluemix, it is possible to create a project. The screen shot below shows the information needed to do this. Basically it has to have a name, how the source code should be managed, how the project template should look like. There is also a choice to integrate Bluemix with the project.

For the following part of this blog I am assuming that Jazz SCM was chosen.

New DevOps Services ProjectFor the Bluemix integration provide the organization – basically the Bluemix ID and the password.

Clicking the Create button creates a RTC project (which is working under the hood of DevOps Services).

On the overview page, you can select to edit the code, track and plan work with work items, and configure and manage build and deployment.

Configure Eclipse ProjectThere is also a “Configure Eclipse Client” choice available. Clicking at it provides the information of an invitation that can be used in the RTC Eclipse client to set up the connection.

Configure Eclipse ClientJust copy the invitation data and paste it into the ‘Accept Invitation’ action, provide the password and the connection is created. We will look into the next steps done with Eclipse later.

Enabling the Bluemix Integration

Switch to the Build & Deploy section using the button. This page allows to configure the build and deploy mechanism, request a new build and deploy and view the deployment status.

Configure Deploy and BuildThe Build and Deploy has basically two settings. Click Simple to select the Simple setting which are adequate for now (this means I haven’t been able to use the advanced settings). Then click the configure button.

Configure DeploymentThis basically defines the structure needed to deploy an app.

The integration expects the manifest.yml in the root folder in the jazz SCM system. Since there currently is no example code, the first builds&deploys will probably fail.

Jazz SCM in the Project Web UI

Switching to the Edit Code page allows to access the SCM information.

Please note: I had issues with seeing the stream information, versioned files and other data with the latest Version of the Firefox Browser ESR (31.2.0).

Chrome worked for me, so I would suggest to use that browser. It is unclear why, because other users apparently don’t have that problem. It might as well be one of these weird effects we ave to put up with in a browser-based world.

The project creation dialog created a Stream, a repository workspace and a component already. The names are based on the name of the project.

You can browse the repository workspace and create files and folders in the Orion editor in the web UI and deliver your changes to the stream to be deployed.

My task was doing this with the Eclipse client, so there I went first.

Jazz SCM in the Eclipse Client

There is a description for this step that I could find here in the documentation. However, I had problems with performing them. This might be different today, however, if you run into anything, it might have similar reasons.

At this point the assumption is that the invitation from DevOps Services has been used to create a repository connection and the client is logged into the project.

As a first step, a new repository workspace is needed. The easiest way to create one is to find the stream in the Team Artifacts view and create the repository workspace from that. This creates the repository workspace and sets the default and current flow back to the stream. Tip: Name the repository workspace e.g. putting ‘Eclipse’ into the workspace name. This is to not confuse this workspace with the one used by the Web UI in the Orion editor. The reason is that repository workspaces are not designed to support one instance to be loaded and modified multiple times in different places (streams are designed for this).

Next step would be to load the repository workspace. Before attempting this, keep in mind that the Build&Deploy step assumes the manifest.yml file to be in the root folder. To achieve that using the Eclipse client and RTC Jazz SCM, there is only one option: Load the component as root folder as shown below. Trying this however, failed for me the first time around. The reason for that is that the default name of the component is derived from the project name and has a pipe ‘|’ symbol in the name. This is not allowed as name in a file or folder on the filesystem (Windows at least). Best approach is to rename the component to some useful mane. At least replace the pipe symbol by a valid one, for example a dash.

After this has been done the component can be loaded.

Load Repo Workspace ComponentIn the second step of the load wizard select the component to be loaded and press finish.

Select Load Repo Workspace Component As FolderWhile loading the data to disk, the RTC Eclipse client creates an artificial project file to mark this folder as an Eclipse project. dependent on the scenarios one wants to perform later, one might or might not want this file to be checked into version control. If one would like to have Eclipse projects on a deeper level, the file could get into the way.

Since the file is always created if the data is loaded this way, I added the file to the Jazz ignore file.

It is now possible to add the files for the application. For example the files from the example from Bluemix from my last post can be used as shown below. This would for example look like below:

Example File Structure

Why this structure? The project.json file is from configuring the project. It contains the property for the project name. I left it there.

The manifest.yml file is needed for the boilerplate/runtime our sample is using. It need to be in the root folder. It is specific to how Bluemix builds and deploys. In the example above I basically moved the original the manifest.yml from the enclosed eclipse project rsjazz01 into the root folder. Then I changed the path to pint into my Eclipse project/folder rsjazz01.  The content is changed to reflect the path to the Node.js project in the sub folder rsjazz01.

Manifest FileIf the path set above, would be just the root folder, the package.json file would be required also in the root folder. As it is above the file is needed in the sub folder.

The way it is now, would allow to load the repository workspace to find the rsjazz01 folder as node.js project and do local debugging on it.

Working with the Code

Once the general structure is set up, it is possible to edit the code in the Web UI as well as in the Eclipse client. Once you deliver the code to the stream it gets automatically built and deployed. Delivery would usually require a work item connected to the code change for traceability.

Build And DeployThe application is also accessible for testing and, of course monitoring in Bluemix.

Pro and Con’s

Looking at this post and the Bluemix post, there are obviously several valid approaches. The approach described here allows to have one application developed with one DevOps Services RTC project and have a continuous build and deploy for free.

The approach described in the Bluemix post, would allow to use Eclipse to work on several projects and actually manage the work and code in one or more DevOps Services RTC projects, as best fits. If I want to manage multiple applications in one RTC project, the automatic build and deployment would not be available. That, however can easily be scripted into continuous integration build scripts as well.

Summary

I hope this and the Bluemix post, provide you with some insight about how the DevOps Services and Bluemix work together and how you can user Eclipse and RTC to develop your applications.

Creating CLM Links With Back Link Between Work Items

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

*Update* The post A RTC WorkItem Command Line Version 2 contains downloadable code that performs most of the activities required for reading and modifying work items, including the creation of all kinds of links. The interesting code can be found in the com.ibm.js.team.workitem.commandline.helper package in the class WorkItemHelper. All techniques described below are used there. You can familiarize yourself with the concepts in this post and then look into that project for how it is used.

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

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

License

As always, the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license, which basically means you can use it for internal usage, but not sell. Remember that this code comes with the usual lack of promise or guarantee. Enjoy!

Just Starting With Extending RTC?

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

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

To keep it simple this example is, as many others in this blog, based on the Jazz Team Wiki entry on Programmatic Work Item Creation and the Plain Java Client Library Snippets. The example in this blog shows RTC Client API.

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

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

Creating Back Links – Limitations for Versions Prior to 4.0.6

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

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

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

Creating Back Links on Saving a Work Item

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

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

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

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

Creating Back Links – Client API Example

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

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

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

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

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

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

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

private static class LinkTrackingWorkItemOperation extends
		WorkItemOperation {

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

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

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

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

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

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

Creating Back Links – Server API Example

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

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

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

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

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

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

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

Summary

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

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

Work Item Command Line Client to Add a Comment

Yesterday I was asked to help a project that is incrementally migrating to Rational Team Concert with a small command line tool allowing to add comments to a work item. The team has switched to work items already and this tool is supposed to be used in some automation and called from another tool that is not yet replaced by RTC.

I had not yet worked with work item comments that much, except printing them and was interested in understanding how hard it would be to find the API involved. I made some nice experience doing so, which I would like to share.

Just Starting With Extending RTC?

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

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

To keep it simple this example is as many others in this blog based on the Jazz Team Wiki entry on Programmatic Work Item Creation. The example shows client API.

License

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.

Operation to Add a Comment

As usual I decided to go with a WorkItemOperation to add the comment and update the work item. To do that, I created an inner class WorkItemAddComment extending WorkItemOperation. Well, to tell the truth, I grabbed the whole initial code from another example like published in Upload Attachments To Work Items.

Then I looked into implementing the execute method, that is called when the operation is performed. Since I did not have code other than printing comments, I first used IComments comments = workItem.getComments() to get the comments.

Now I needed to find the API to create an IComment. So I used search for references as described here to look at references where IComment was created. Surprisingly I found the interface IComments provides the createComment() method.I could have found it right away if I had looked. But the learning here is, if you set up your environment as described here and here, and follow the tips to search, you can easily find it. Not much brainpower needed here.

The createComment() method needs an IContributor object for the person that is named as creator of the comment and an XMLString for the comment itself. I decided to change the constructor of the operation to pass an IContributor and a String and store them in fields, to have them available in the execute() method.

Finally it is necessary to add the new comment to the comments retrieved from the work item. All the save and update mechanism is handled in the WorkItemOperation.

To be able to update the work item in the execute() method, the constructor also needs to pass a load profile to the superclass. I started with using the full profile but optimized it later to load with a custom load profile based on the small profile with the Comments property as extension.

The resulting code is shown below.

	private static class WorkItemAddComment extends WorkItemOperation {

		private String fComment;
		private IContributorHandle fCommenter;

		public WorkItemAddComment(IContributorHandle commenter, String comment) {
			super("Add Comment to Work Item", IWorkItem.SMALL_PROFILE.createExtension(Arrays.asList(new String[] { IWorkItem.COMMENTS_PROPERTY })));
			fComment = comment;
			fCommenter = commenter;
		}

		@Override
		protected void execute(WorkItemWorkingCopy workingCopy,
				IProgressMonitor monitor) throws TeamRepositoryException {
			IWorkItem workItem = workingCopy.getWorkItem();

			IComments comments = workItem.getComments();
			IComment newComment = comments.createComment(fCommenter,
					XMLString.createFromPlainText(fComment));
			comments.append(newComment);
		}
	}

Call the new Operation

The new operation takes two parameters in the constructor.

  • The IContributorHandle of the user to show as creator of the comment
  • A string that is the text in the comment

The operation gets called and executed like below.

	WorkItemAddComment operation = new WorkItemAddComment(commentUser,commentText);
	operation.run(workItem, monitor);
	System.out.println("Modified work item " + workItem.getId() + ".");

Get The Required Data

To call the code above, we need to get the user creating the comment and the work item to update. My final direction was, that I wanted to be able to just provide the repositoryURI, the credentials to log in, a work item ID and a comment string to be able to create the comment. In this scenario the user that runs the command line tool would be creator of the comment. As an enhancement I wanted to be able to pass the user ID of the creator of the comment.

The run method finally looks like this code:

private static boolean run(String[] args) throws TeamRepositoryException {
	boolean result = false;
	if (args.length  6) {
		System.out
				.println("Usage: AddComment      []");
		return result;
	}

	String repositoryURI = args[0];
	String userId = args[1];
	String password = args[2];
	String idString = args[3];
	String commentText = args[4];
	String commenterID = null;
	if (args.length == 6) {
		commenterID = args[5];
	}

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

	IContributor commentUser = null;
	if (null != commenterID) {
		try {
			commentUser = teamRepository.contributorManager().fetchContributorByUserId(
					commenterID, monitor);
		} catch (ItemNotFoundException e) {
		}
	}
	if (commentUser == null) {
		commentUser = teamRepository.loggedInContributor();
	}

	// Use IWorkItemClient or IWorkItemCommon
	IWorkItemCommon workItemCommon = (IWorkItemCommon) teamRepository
			.getClientLibrary(IWorkItemCommon.class);
	int id = new Integer(idString).intValue();
	IWorkItem workItem = workItemCommon.findWorkItemById(id,
			IWorkItem.SMALL_PROFILE, monitor);

	if(null!=workItem){
		WorkItemAddComment operation = new WorkItemAddComment(commentUser,
				commentText);
		operation.run(workItem, monitor);
		System.out.println("Modified work item " + workItem.getId() + ".");
		result=true;
			
	} else{
		System.out.println("Can not find work Item " + idString + ".");
	}
	teamRepository.logout();
	return result;
}

What it does, is checking and getting the parameters first.

The code then logs into the repository. If a second user ID is available for the commenter, the code tries to get the related contributor. If this fails the code falls back to the automation user ID by getting the IContributor logged in.

Then the code gets the IWorkItemCommon client library to find the work item by the ID passed in the call. If all succeeds the operation is called to update the work item and we are done.

The Rest of The Code

You can grab the rest of the code from Upload Attachments To Work Items. The code is also available in the Jazz In Flight project at JazzHub in the project com.ibm.js.team.workitem.automation.examples in the Extension Development Stream in the RTC PlainJava Automation component.  Once you have access you can get the code. You can also request to join the project and provide your own solutions there.

Calling The Code From The Command Line

The code can be called like below from the command line, provided JAVA_HOME is set and the Plain Java Client Libraries are installed in the second location and the code is compiled. The code below can be placed in a batch file which is called in the root of the eclipse project.

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

See the README.TXT in the snippets folder of the Plain java Client Libraries for instructions for UNIX like operations systems.

Please Note: I had to explicitly point to the JRE, if the JDK did not provide an lib/ext folder.

Summary

As always I hope this code is useful to anyone. I also hope that the tips on searching the API helps others to explore the API as well. Please keep in mind, the code is not thoroughly tested and might need some polishing if you want to use it.

RTC Process Enactment Workshop – Customize Attributes Using JavaScript

Almost all customers need to customize their RTC process, especially Work Items. Especially Attribute Customization, including JavaScript based customization is very popular on the Jazz.net forums. There are a lot of questions around how these customizations can be done and what is actually possible.

Since this is so popular Jim Ruehlin, Jorge Diaz and I made an effort to create a workshop that explains the concepts involved. The Process Enactment Workshop was published the first time in November last year. When it was first published we had finalized 4 labs.

  • Lab 1: Set Up the Process Enactment Environment
  • Lab 2: Understand the Process Development Lifecycle
  • Lab 3: Configuring Work Items
  • Lab 4: Work Item Customization

Lab 4 talks only about the Attribute Customization that can be done using the built in declarative customization.

Yesterday we published Lab 5. This Lab talks about Work Item Customization with JavaScript. The lab uses examples to explore the JavaScript related capabilities. We tried to pick some examples that would be close to requests we have seen in the forum. In addition there is a section about what can be done with JavaScript today – and what is not possible – as far as we can tell.

JavaScript Debugging is described in Millard’s Article on debugging JavaScript.

I hope we addressed interesting examples that help with real world challenges. It is possible to run the whole workshop and it should also help if you just read specific sections. Enjoy!

PS:

Jorge and Jim have their own blogs that provide interesting solutions and insight into using RTC and the Jazz based solutions.

Do not Modify the Triggering Element in an OperationAdvisor

Don’t modify the element that triggers your OperationAdvisor! The API is not designed to support that. You can do this in a participant.

Get a comprehensive overview of the rules and how this works in the Team Process Developer Guide.

I met with the work item team in Zurich two days before and we had some discussion about automation around work items in several areas. This lead to looking into the API for the extension point com.ibm.team.process.service.operationAdvisors and we found that the class providing this actually states that you should not modify the object that triggers the operation advisor.

The Wiki topic Process Execution of Operations also explains that, and why client side advisors and participants must not modify information in the repository.

See the documentation of com.ibm.team.process.common.advice.runtime.IOperationAdvisor below:

/**

* Operation advisors are run before an operation is invoked to decide whether

* or not the operation should be executed. Advisors check conditions and

* report problems via the collector they are given. If an advisor reports a

* serious problem with an operation, the operation will not be executed (though

* subsequent advisors may still be checked).

*

* Advisors may not make modifications to data which is persisted in the

* repository. Clients wishing to participate in operations by modifying data

* should implement an {@link IOperationParticipant} instead.

*

* Operation advisors are contributed on the client and server via the

* com.ibm.team.process.client.operationAdvisors extension-point and the

* com.ibm.team.process.service.operationAdvisors extension-point

* respectively.

*

Why is that important? For example imagine you have the intention to check for a work item state change, and you want to add approvals for specific state changes. You could use an operation participant for that as described in this post.

You could however also have the idea to do that in an operation adviser. If you do that, it violates the contract of the extension point. The extension point does not check that and it might actually work, but there might be ill effects or, if the extension point starts checking in the future, your extension might stop working.

One example where you might have ill effects is that the manipulation and save of the work item will not cause a second save and thus also bypass any other Advisor you might have in place. If you had an advisor that prevented approvals from being added to work items, it would not detect that change.

In general, if you want to modify data, use an operation participant.

Related Posts

RTC Update Parent Duration Estimation and Effort Participant

Resolve Parent If All Children Are Resolved Participant

A Create Approval Work Item Save Participant

Jazz.net article about creating operation Advisors

The RTC WorkItem Server Link API – Linking to Work Items and Other Elements

Yesterday, I blogged about the RTC Client Link API. I excluded the server API, mainly because I realized I was not able to access the references from a WorkItemWorkingCopy on the server. The server API is simply different. I missed looking into an example that I had created some years ago, where I had already solved the issue. So here is the “missing link”.

*Update* See the post Creating CLM Links With Back Link Between Work Items for some new information on CLM links between work items.

*Update* Creating the Links using the ILinkServiceLibrary does not trigger operational behavior.

*Update* I took a deeper look at what to do with URI references on the server.

*Update* Use the new method instead of ILinkServiceLibrary to create links that can be governed by operational behavior.

*Update* Please find some of the code in the download at the post Resolve Parent If All Children Are Resolved Participant.

  • Update * This forum post shows the code that links a work item with a RTC SCM change set.

License and how to get started with the RTC API’S

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. Enjoy!

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

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

To keep it simple this example is, as many others in this blog, based on the Jazz Team Wiki entry on Programmatic Work Item Creation and the Plain Java Client Library Snippets. The example in this blog shows RTC Client and Common API.

Accessing References on the Server

I found two ways to access references for work items on the server. The post RTC Update Parent Duration Estimation and Effort Participant provides an example that shows how to use the information about existing and new references provided by the ISaveParameter operation. For example using this code:

IWorkItemReferences newRreferences = saveParameter.getNewReferences();

The code provides you with the references for the state of the work item. If you want to access the references for the old work item, or if you just have a work item (for instance a parent) and want the references for that, you have to take a different approach as presented below.

IWorkItemReferences oldReferences=null;
IAuditable oldState = saveParameter.getOldState();
if(oldState!=null){
	IAuditableCommon common = (IAuditableCommon)getService(IAuditableCommon.class);
	IWorkItem oldItem = (IWorkItem)common.resolveAuditable(oldState, IWorkItem.FULL_PROFILE, monitor);
	IWorkItemServer workItemServer = getService(IWorkItemServer.class);
	oldReferences = workItemServer.resolveWorkItemReferences(oldItem, monitor);
}

The code gets the IAuditable from the old state. If the old state is not null (there was a state), the code resolves the IAauditable to the IWorkItem. then it uses the IWorkItemServer service to get the references. Working with the references is identical to the client, except Creating a reference.

Handling CALM or URI References on the server

*Update* I took a deeper look at what to do with URI references.

The code below is the server API replacement for analyzeReferenceTarget() in The RTC WorkItem Client Link API – Linking to Work Items and Other Elements. All other methods to analyze the references found in the post can be used on the server too. The difference on the server is that the client library used in analyzeReferenceTarget() in the post The RTC WorkItem Client Link API – Linking to Work Items and Other Elements needs to be replaced by a service.

The code below tries to find the other end of an URI reference. Those references are used for CALM links such as “Tracks”. In case the other end is a work item it uses the location information to get the work item.

/**
* Further analyze an item referenced by an URI
* @param iReference
*/
public void analyzeReferenceTarget(IReference iReference) {
	URI uri = iReference.createURI();
	try {
		System.out.println(" Resolving URI: " + uri.toString());
		// get the location from the URI
		Location location = Location.location(uri);
		// resolve the item by location
		IAuditableCommon common = getService(IAuditableCommon.class);
		IAuditable referenced = common.resolveAuditableByLocation(
			location, ItemProfile.createFullProfile(
			location.getItemType()), null);
		// look for a referenced work item
		if (referenced instanceof IWorkItem) {
			IWorkItem referencedWI = (IWorkItem) referenced;
			System.out.println(" Resolved URI (resolve): "
				+ uri.toString() + " to: " + referencedWI.getId()
				+ " " + referencedWI.getState2().toString());
		}
	} catch (TeamRepositoryException e) {
	e.printStackTrace();
}
System.out.println(" Resolved URI: " + uri.toString());
}

Creating References on the Server

*Update* Creating the Links using the ILinkManager does not trigger operational behavior.Use creating IReferences instead and save them with IWorkItemServer.saveWorkItem3(). I also ran into a problem with CLM links such as Tracking work item links. I will post a solution as soon as I have one.

This was the hardest part really.

*UPDATE*

I had to write some code for a customer and I needed to create CLM links like Tracks. I used the code I had – the one published in the second next block. It did not work as expected. The issue was, the links where created, but I could not delete them anymore. I had to investigate, talked to one of our developers and we finally came up with the new code below.

/**
 * Link the trigger and the target work item
 * @param sourceWorkItem     the work item to link to
 * @param targetWorkItem     the work item to link to
 * @param monitor
 * @return
 */
private linkWorkItemsCLM(IWorkItem sourceWorkItem, IWorkItem targetWorkItem, IProgressMonitor monitor) {
	fWorkItemServer = getService(IWorkItemServer.class);
	// Get the references for the source work item, we need it to add new links
	IWorkItemReferences targetReferences = fWorkItemServer
				.resolveWorkItemReferences(resolvedTriggerItem, monitor);
	IEndPointDescriptor tracksEndpoint = ILinkTypeRegistry.INSTANCE
			.getLinkType(WorkItemLinkTypes.TRACKS_WORK_ITEM)
			.getTargetEndPointDescriptor();
	Location location = Location.itemLocation(targetWorkItem,
			this.getPublicRepositoryURL());
	IReference targetEndpoint = IReferenceFactory.INSTANCE
			.createReferenceFromURI(location.toAbsoluteUri());
	// The target work item is new, no need to check for duplicates
	targetReferences.add(tracksEndpoint, targetEndpoint);

	// Save the sourceWorkItemwork item with the links we created
	IStatus saveStatus = fWorkItemServer.saveWorkItem3(sourceWorkItem,
			targetReferences, null, null);
}

The code above is able to successfully create CLM and other links from work items to other items, including work items. The code above is different from the code below I came up with first.

It uses the work item server to save the work item, instead of using the ILinkService to create and save the link. That way, operational behavior is called for the save operation and operational behavior can govern the creation of these links. The code below shows how to call the code.

// Load the new trigger work item so that we can modify it and don't get
// stale data
fWorkItemServer = getService(IWorkItemServer.class);
ItemProfile loadProfile = IWorkItem.SMALL_PROFILE
	.createExtension(Arrays.asList(new String[] { IWorkItem.TARGET_PROPERTY }));
IWorkItem sourceWorkItem= (IWorkItem) fWorkItemServer
	.getAuditableCommon()
	.resolveAuditable(workItem, loadProfile, monitor)
	.getWorkingCopy();
linkWorkItemsCLM(IWorkItem sourceWorkItem, IWorkItem targetWorkItem, IProgressMonitor monitor)

In the above code a Location was used to create the target endpoint. This location needs the public repository URI, otherwise the work item won’t be linked properly. The code above works across repositories, if you provide the right public repository URI for the target work item. In the code above the assumption is that both work items are in the same repository.

If you want to link work items with work item references like parent-child references in the same repository, you can use the code below. It avoids having to create the reference from an URI.

IEndPointDescriptor tracksEndpoint = ILinkTypeRegistry.INSTANCE
	.getLinkType(WorkItemLinkTypes.PARENT_WORK_ITEM)
	.getTargetEndPointDescriptor();
IReference targetEndpoint = IReferenceFactory.INSTANCE
	.createReferenceToItem(targetWorkItem);

Note: Don’t use this method, as it avoids triggering operational behavior on save.

In the past, when I dug into the SDK and found bits and pieces. I dug around on Jazz.net and finally found this answer on Jazz.net which I shamelessly used to build my example code. However that was not enough and I had to refine it to get it working properly.

// Get the reference factory to create references
IReferenceFactory refFactory = IReferenceFactory.INSTANCE;
IReference source = refFactory.createReferenceToItem(parent);
IReference target = refFactory.createReferenceToItem(blocked);
// get the link service to have access to the ILinkServiceLibrary
ILinkService linkService = getService(ILinkService.class);
// get the ILinkServiceLibary
ILinkServiceLibrary linkServiceLibrary = (ILinkServiceLibrary) linkService
	.getServiceLibrary(ILinkServiceLibrary.class);
// Create the link
ILink link = linkServiceLibrary.createLink(
WorkItemLinkTypes.BLOCKS_WORK_ITEM, source, target);
// Save the link
linkServiceLibrary.saveLink(link);

Note, please don’t forget to declare the services you use in server extensions as requiredService in the plugin XML as described here.