RegisterLog In to Jazz.net dW

Integrating Rational Team Concert with an Activity Stream Service

I was at IBM Innovate 2011 in Orlando this year demonstrating a Social Business proof of concept. It was a mobile demonstration, running on an iPad and iPhone, that used Open Services for Lifecycle Collaboration (OSLC), OpenSocial, and Activity Streams to create a portable embedded experience in the activity stream for all your Application Lifecycle Management tools. You can learn more about the Innovate 2011 proof of concept (and watch the video) on the OpenSocial Blog.

As part of the demo, you would resolve a Defect work item in Rational Team Concert. This operation would post a new social activity to an Activity Stream within your enterprise social application (a morning report) running on an iPad. You could then view and interact with those Work Items without leaving your morning report. Several conference attendees asked, "How did you make Rational Team Concert post to the activity stream?" It was easy! This is a great and simple example of how you can start extending Rational Team Concert in novel ways.

In this article you will learn how to create an Operation Participant for Work Item Save that connects to an activity stream. You will also learn how to link in a graphical user interface, an aspect editor, for configuring the participant.

Prerequisites

The Eclipse plug-ins, features, and update site projects with the full source code used in this example and are also available for download.

Eclipse Development Knowledge

This example makes use of extension points provided and documented by RTC. So some familiarity with Eclipse plug-in development and the use of Eclipse extension points is required. Plenty of good resources on Eclipse plug-in development exist on the web, but one such resource is available on developerWorks.

Working RTC Development Environment

You will be creating extensions that plug into the Jazz Team Server and the RTC Client for Eclipse. So you will need to follow the instructions for setting up a RTC development environment within the RTC SDK wiki.

Deployed Activity Stream service

In order to have a fully working system, you will need to point at a deployment of an Activity Stream service. Apache Shindig was the sample implementation of the Activity Stream service that was used for the development of the original demonstration and this article.

At the time of this writing, it is necessary to build the latest development version of Apache Shindig (http://svn.apache.org/repos/asf/shindig/trunk/) in order to get the most up to date Activity Stream implementation. You will need to use Apache Maven to build Apache Shindig. Building from source will not be necessary once Apache Shindig 3.0.0 is available.

How this integration for Rational Team Concert will work

We will allow social rules to be configured within an RTC Team Area. We will implement a server component that will participate in Work Item save operations. This participant will compare the current Work Item save with the list of social rules configured in the Team Area. When we have a matching social rule, we will use the information in the social rule to generate a message that gets posted to an Activity Stream service that could be part of an existing social network. This example will use the JSON Activity Streams 1.0 standard to represent these messages as Activity Entries.

Creating our Social Operation Participant

The first step in extending Rational Team Concert is identifying the server extension point we want to use. The purpose of this extension is to generate activities when Work Items get saved under preconfigured circumstances. So the best match for our needs will be an Operation Participant extension that will participate in Work Item Save operations. We are using an Operation Participant because they run after the operation has been invoked. This also means that if the operation failed because it was blocked by an advisor or a failure our participant will not run.

Operation participant extension

   <extension
         point="com.ibm.team.process.service.operationParticipants">
      <operationParticipant
        class="com.ibm.opensocial.process.service.SocialRuleOperationParticipant"
        id="com.ibm.opensocial.socialruleoperation"
        name="Social Rule Participant"
        operationId="com.ibm.team.workitem.operation.workItemSave">
      </operationParticipant>
   </extension>

Server-side Operation participants use the com.ibm.team.process.service.operationParticipants extension point. The identifier for our participant extension is com.ibm.opensocial.socialruleoperation which we will see again later. The operation identifier for Work Item Save is com.ibm.team.workitem.operation.workItemSave. The class com.ibm.opensocial.process.service.SocialRuleOperationParticipant is the entry point for our extension and it must implement the IOperationParticipant interface.

SocialRuleOperationParticipant class

public class SocialRuleOperationParticipant implements IOperationParticipant {
  
  private final HttpClient client = new HttpClient();
  public static final String WI_TYPE = "wiType"; //$NON-NLS-1$
  public static final String WORKFLOW_ACTION = "workflowAction"; //$NON-NLS-1$
  ...
  
  public SocialRuleOperationParticipant() {
    client.getParams().setParameter("http.useragent", "RTC 3.0.1 Social Integration");
  }
    
  public void run(AdvisableOperation operation,
      IProcessConfigurationElement participantConfig,
      IParticipantInfoCollector collector, IProgressMonitor monitor)
      throws TeamRepositoryException {
    IProcessConfigurationElement[] rules = participantConfig.getChildren();
    Object data= operation.getOperationData();
    if (data instanceof ISaveParameter) {
      try{
        ISaveParameter savedItem = (ISaveParameter)data;
          IAuditableCommon auditableCommon = savedItem.getSaveOperationParameter().getAuditableCommon();
          IWorkItem wi = (IWorkItem)savedItem.getNewState();
          for (IProcessConfigurationElement rule : rules) {
            if(wi.getWorkItemType().equals(rule.getAttribute(WI_TYPE)) 
                && savedItem.getWorkflowAction() != null 
                && savedItem.getWorkflowAction().equals(rule.getAttribute(WORKFLOW_ACTION))){
              postToActivityStream(monitor, rule, savedItem, auditableCommon, wi);
            }   
          }
      } catch(Throwable t) {
        t.printStackTrace();
      }
    }
  }
  ...
    
}

The run() method gets called on each Work Item save. We want our extension to be more flexible than that, so we allow a project administrator to create rules in the project process configuration. The process configuration element associated with this operation participant is passed by the participantConfig parameter. The children of that element are the social rules that we match against to determine what messages get created and where to post them. So for all social rules that match the given work item type and action, we will post a new activity using the Apache HttpClient in the postToActivityStream() method.

Operation participants do not become active until they have been added to the Team Area. This allows individual teams to configure for themselves how different operations should behave or if they are applied. So our Social Operation Participant will not become active until it has been added as a Follow-up action to the Save Work Item (Server) operation. You can add the Social Operation Participant by modifying your Process Configuration for your team area (as seen below) once you have deployed the extension to your Jazz Team Server.

Adding Social Rule Participant as a Follow-up action

Creating the Aspect Editor for the "Social" Operation Participant

The social rules in this example use several pieces of information.

  • Social Rule identifier - A unique identifier that can be used to reference a particular social rule
  • Activity Stream URI - Location of the Activity Stream service where we want to post new activity entries associated with this rule
  • Work Item Type identifier - A unique identifier for the work item type that this rule will match
  • Workflow Action identifier - A unique identifier for the workflow action that this rule will match
  • Message Template - A standardized message template that will form the text included with generated activity entries

How are these pieces of information used? For each social rule, when the work item being modified matches the Work Item Type and Workflow Action defined, the system generates an activity entry using the Message Template and posts it to the Activity Stream URI.

That's a lot of information. We could just have users enter this information manually into the process configuration source, or we can create a more convenient graphical user interface called a Process Aspect Editor. Creating an aspect editor provides an integrated user interface for project administrators to configure our extension without having to directly modify the process configuration source. You contribute this user interface through a RTC Client extension point.

Process Aspect Editor Factory extension point

   <extension
         point="com.ibm.team.process.ide.ui.processAspectEditorFactories">
      <factory
            aspectId="com.ibm.opensocial.socialruleoperation"
            class="com.ibm.opensocial.process.ui.OpenSocialProcessAspectEditorFactory">
      </factory>
   </extension>

Process aspect editor factories are registered through the com.ibm.team.process.ide.ui.processAspectEditorFactories extension point. We need to register our factory to the com.ibm.opensocial.socialruleoperation aspect, which is how we defined our Social Operation Participant above.

OpenSocialProcessAspectEditorFactory class

public class OpenSocialProcessAspectEditorFactory implements IProcessAspectEditorFactory {

	public ProcessAspectEditor createProcessAspectEditor(String processAspectId) {
		if(processAspectId.equals("com.ibm.opensocial.socialruleoperation")){
			return new SocialRuleOperationEditor();
		}
		return null;
	}

}

The factory creates a new SocialRuleOperationEditor instance as needed by the RTC Client. The factory must implement the IProcessAspectEditorFactory interface.

SocialRuleOperationEditor class

public class SocialRuleOperationEditor extends OperationDetailsAspectEditor {
	
	public static final String ACTIVITY_URI = "activityUri"; //$NON-NLS-1$
	public static final String ID = "id"; //$NON-NLS-1$
	public static final String WI_TYPE = "wiType"; //$NON-NLS-1$
	public static final String WORKFLOW_ACTION = "workflowAction"; //$NON-NLS-1$
	public static final String MESSAGE_TEMPLATE = "messageTemplate"; //$NON-NLS-1$
	public static final String TYPE = "social-rule"; //$NON-NLS-1$
	...
	
	public List<HashMap<String,String>> rules = new ArrayList<HashMap<String,String>>();
	...

	@Override
	public void restoreState(IMemento memento) {
		IMemento[] mems = memento.getChildren(TYPE);
		for (IMemento iMemento : mems) {
			HashMap<String, String> rule = new HashMap<String, String>();
			rules.add(rule);
			rule.put(ID, iMemento.getString(ID));
			rule.put(ACTIVITY_URI, iMemento.getString(ACTIVITY_URI));
			rule.put(WI_TYPE, iMemento.getString(WI_TYPE));
			rule.put(WORKFLOW_ACTION, iMemento.getString(WORKFLOW_ACTION));
			rule.put(MESSAGE_TEMPLATE, iMemento.getString(MESSAGE_TEMPLATE));
		}

	}

	@Override
	public boolean saveState(IMemento memento) {
		for (HashMap<String, String> rule : rules) {
			IMemento ruleMem = memento.createChild(TYPE);
			ruleMem.putString(ID, rule.get(ID));
			ruleMem.putString(WI_TYPE, rule.get(WI_TYPE));
			ruleMem.putString(ACTIVITY_URI, rule.get(ACTIVITY_URI));
			ruleMem.putString(WORKFLOW_ACTION, rule.get(WORKFLOW_ACTION));
			ruleMem.putString(MESSAGE_TEMPLATE, rule.get(MESSAGE_TEMPLATE));
		}
		return true;
	}
	
	@Override
	public void createControl(Composite parent, FormToolkit toolkit) {
		...
	}
	
}

Aspect editors for operation participants and preconditions should extend the OperationDetailsAspectEditor class. Aspect Editors use an IMemento for storing and restoring the configuration state. The RTC Client handles serializing that state into the process configuration XML. The createControl() method is what creates the actual user interface.

A quick look at the Social Rule Aspect Editor

Social Rule Aspect Editor screenshot

The area bounded in red on the above image is the interface contributed from SocialRuleOperationEditor. The rest of the interface is controlled by the RTC Client. Remember that this editor only becomes available for project areas on servers with our Social Operation Participant installed.

Installing the Process Aspect Editor and the Operation Participant

Extensions to the RTC Client and the Jazz Team Server are done through the use of Eclipse update sites. A pair of Eclipse feature projects and an update site project are included in the download. The example update site project is called com.ibm.opensocial.process.server.site. Building this update site project will build the two features and deploy them within the update site. You can then install the com.ibm.opensocial.socialrule.client.feature, which contains the aspect editor, into RTC Clients using Help > Install New Software... and adding the new update site.

The update site can also be used to install the com.ibm.opensocial.socialrule.feature feature into the CCM application on Jazz Team Servers. Check out the Tomcat section in the development environment setup wiki for details on using provision profiles to deploy Jazz Team Server extensions. The provision profile used in development of this example is provided below as reference. The example assumes that the update site has been copied to the server/conf/ccm/sites/ directory.

server/conf/ccm/provision_profiles/social.ini

url=file:ccm/sites/com.ibm.opensocial.process.server.site
featureid=com.ibm.opensocial.socialrule.feature

After the server extension is installed and it can be configured to post activities to an activity stream service. For the purposes of the demo, we used an activity stream implementation from the latest development version of Apache Shindig 3.0. So that when a Defect work item got resolved, it would post a new activity to my Shindig instance and it would appear in the user interface.

Morning Report screenshot with new activity entry

The JSON activity entry representation used in the example code is based upon the JSON Activity Streams 1.0 specification.


For more information


About the author

Matthew Marum worked as a Software Engineer within IBM Rational working on products like Rational ClearQuest and Rational Team Concert for over 5 years. He is now in IBM Software's Strategy organization doing work with collaborative web standards like OpenSocial and Activity Streams. He can be contacted at mgmarum@us.ibm.com.

Feedback
Was this information helpful? Yes No 4 people rated this as helpful.