Custom Process Advisor using RTC SDK
Hi all,
I followed the content of the article referenced below to create a custom process advisor plugin that is designed to walk the relationship of linked work items. I am using RTC 3.0 and I did make the necessary translations from the article (written against 2.x) and was able to get the example in the article fully deployed and working. The problems started after I needed to add several imports to create the functionality I am looking for. The relevant custom source code is below.
http://jazz.net/library/article/495/
When it runs I get the following error in the process advisor:
An unhandled exception occurred during "Prohibit Save (Hello World Advisor)".The service 'helloworldadvisor.HelloWorldProhibitSave@245c245c' failed to find the required service 'interface com.ibm.team.links.common.service.ILinkService'. Check <prerequisites> in plugin.xml.
I Googled this and looked it up in the forums and it appears that others are saying that I would have to manually edit the plug.xml file. This seems an unlikely task to me. So, I tried anyway but it had no effect. I'm sure I did something wrong because I didn't know what to enter for some of the element attributes.
When I looked up the jar that contains the offending interface I scanned the tomcat directories and was unable to find it on the server. That makes me think that perhaps it needs to be packaged with my plugin. No idea how I would do that.
Hoping some can point out what I need to change in my plugin, feature or site update project.
The source code is follows.
I followed the content of the article referenced below to create a custom process advisor plugin that is designed to walk the relationship of linked work items. I am using RTC 3.0 and I did make the necessary translations from the article (written against 2.x) and was able to get the example in the article fully deployed and working. The problems started after I needed to add several imports to create the functionality I am looking for. The relevant custom source code is below.
http://jazz.net/library/article/495/
When it runs I get the following error in the process advisor:
An unhandled exception occurred during "Prohibit Save (Hello World Advisor)".The service 'helloworldadvisor.HelloWorldProhibitSave@245c245c' failed to find the required service 'interface com.ibm.team.links.common.service.ILinkService'. Check <prerequisites> in plugin.xml.
I Googled this and looked it up in the forums and it appears that others are saying that I would have to manually edit the plug.xml file. This seems an unlikely task to me. So, I tried anyway but it had no effect. I'm sure I did something wrong because I didn't know what to enter for some of the element attributes.
When I looked up the jar that contains the offending interface I scanned the tomcat directories and was unable to find it on the server. That makes me think that perhaps it needs to be packaged with my plugin. No idea how I would do that.
Hoping some can point out what I need to change in my plugin, feature or site update project.
The source code is follows.
package helloworldadvisor;
import org.eclipse.core.runtime.IProgressMonitor;
import com.ibm.team.links.common.service.ILinkService;
import com.ibm.team.links.common.factory.IReferenceFactory;
import com.ibm.team.links.common.IItemReference;
import com.ibm.team.links.common.ILink;
import com.ibm.team.links.common.ILinkCollection;
import com.ibm.team.links.common.ILinkQueryPage;
import com.ibm.team.links.common.IReference;
import com.ibm.team.links.service.ILinkServiceLibrary;
//import com.ibm.team.process.common.advice.IReportInfo;
import com.ibm.team.process.common.advice.IProcessReport;
//import com.ibm.team.process.common.advice.runtime.IParticipantInfoCollector;
import com.ibm.team.repository.service.AbstractService;
import com.ibm.team.repository.service.IRepositoryItemService;
import com.ibm.team.workitem.common.IWorkItemCommon;
import com.ibm.team.workitem.common.model.*;
import com.ibm.team.workitem.common.workflow.IWorkflowInfo;
import com.ibm.team.workitem.service.IWorkItemServer;
import com.ibm.team.process.common.IProcessConfigurationElement;
import com.ibm.team.process.common.advice.AdvisableOperation;
import com.ibm.team.process.common.advice.IAdvisorInfo;
import com.ibm.team.process.common.advice.IAdvisorInfoCollector;
import com.ibm.team.process.common.advice.runtime.IOperationAdvisor;
//import com.ibm.team.repository.common.IAuditable;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.workitem.common.ISaveParameter;
import com.ibm.team.workitem.common.model.IWorkItem;
public class HelloWorldProhibitSave extends AbstractService implements IOperationAdvisor {
public static final String PROBLEM_TYPE = " HelloWorldAdvisor.prohibitSave";
// Constrain the parent and child work item types.
private final static String CHILD_WORK_ITEM_TYPE_ID = "defect";
private final static String PARENT_WORK_ITEM_TYPE_ID = "task";
// The parent must be in a state of "Done" (state id = "s3")
private final static String PARENT_WORK_ITEM_STATE_ID = "3"; //"s3";
// The action to perform on the child (this action id maps to "Released to QA")
private final static String CHILD_RESOLVING_WORKFLOW_ACTION_ID = "com.ibm.team.workitem.defectWorkflow.action.verify";
private final static String CHILD_DEST_WORK_ITEM_STATE = "Released to QA";
public void run(AdvisableOperation operation,
IProcessConfigurationElement advisorConfiguration,
IAdvisorInfoCollector collector,
IProgressMonitor monitor)
throws TeamRepositoryException
{
/*
Object data = operation.getOperationData();
if (data instanceof ISaveParameter) {
ISaveParameter param = (ISaveParameter) data;
IAuditable auditable = param.getNewState();
if (auditable instanceof IWorkItem) {
IWorkItem sourceworkItem = (IWorkItem) auditable;
IAdvisorInfo problem = collector.createProblemInfo(
"Hello World!", "This work item is of type: "
+ sourceworkItem.getWorkItemType(),
PROBLEM_TYPE);
collector.addInfo(problem);
}
}
*/
// If the work item is of type defect and new state is "Release to QA" then
// Get the work item children
// for each work item child
// Set the state to "Release to QA"
// If work item child state could not be set then
// Add a problem and exit
// Part 1 - check input constraints.
//
// Get the work item that is being saved (the parent work item).
ISaveParameter saveParam = (ISaveParameter) operation.getOperationData();
IWorkItem parent = (IWorkItem) saveParam.getNewState();
System.out.println("HelloWorldProhibitSave: 1");
// Types other than PARENT_WORK_ITEM_TYPE_ID are not interesting.
if (!PARENT_WORK_ITEM_TYPE_ID.equals(parent.getWorkItemType()))
{
System.out.println("HelloWorldProhibitSave: 1.1 - parent.getWorkItemType()=" + parent.getWorkItemType());
return;
}
// When the state of the parent is not PARENT_WORK_ITEM_STATE_ID we are not interested in affecting the child work items.
if (!PARENT_WORK_ITEM_STATE_ID.equals(parent.getState2().getStringIdentifier()))
{
System.out.println("HelloWorldProhibitSave: 1.2 - parent.getState2().getStringIdentifier()=" + parent.getState2().getStringIdentifier() + " parent.getState2().toString()=" + parent.getState2().toString());
return;
}
// Part 2 - Get a collection of the child work items.
//
// Get a service to find the linked work items on the parent work item.
ILinkService linkService = getService(ILinkService.class);
ILinkServiceLibrary linkLibrary = (ILinkServiceLibrary) linkService.getServiceLibrary(ILinkServiceLibrary.class);
// Use the service to find all the related work items linked to the parent.
IItemReference workItemRef = IReferenceFactory.INSTANCE.createReferenceToItem(parent);
ILinkQueryPage linkPage = linkLibrary.findLinks(WorkItemLinkTypes.RELATED_WORK_ITEM, workItemRef);
System.out.println("HelloWorldProhibitSave: 2 - Number of child work items found = " + linkPage.getResultSize());
if (linkPage.getResultSize() == 0)
{
// No child work items, nothing to do.
System.out.println("HelloWorldProhibitSave: 2.1");
return;
}
// Part 3 - Process each child work item.
//
// Get some service to help query and save work items.
IRepositoryItemService repositoryItemService = getService(IRepositoryItemService.class);
IWorkItemServer workItemService = getService(IWorkItemServer.class);
IWorkItemCommon workItemCommon = getService(IWorkItemCommon.class);
// Process each child work item.
int count = 0;
ILinkCollection links = linkPage.getAllLinksFromHereOn();
System.out.println("HelloWorldProhibitSave: 3");
for (ILink link : links)
{
// Get the child work item through the link.
IReference otherRef = link.getOtherRef(workItemRef);
IWorkItemHandle childHandle = (IWorkItemHandle) otherRef.resolve();
IWorkItem child = (IWorkItem) repositoryItemService.fetchItem(childHandle, null);
// Process only closed items of type CHILD_WORK_ITEM_TYPE_ID.
System.out.println("HelloWorldProhibitSave: 3.1");
if(CHILD_WORK_ITEM_TYPE_ID.equals(child.getWorkItemType()) && !isClosed(workItemCommon, child))
{
// Change the state and save the child work item.
IWorkItem childWorkingCopy = (IWorkItem) child.getWorkingCopy();
workItemService.saveWorkItem2(childWorkingCopy, null, CHILD_RESOLVING_WORKFLOW_ACTION_ID);
count++;
System.out.println("HelloWorldProhibitSave: 3.2 - processed work item id = " + child.getId());
}
}
// Part 4 - Offer some feedback.
//
System.out.println("HelloWorldProhibitSave: 4");
addAdvisorInfo(
IProcessReport.OK,
"Saved child defects.",
count + " defects where moved to state \"" + CHILD_DEST_WORK_ITEM_STATE + "\"",
collector);
}
private boolean isClosed(IWorkItemCommon workItemCommon, IWorkItem workItem)
{
if (workItem != null)
{
Identifier<IState> state= workItem.getState2();
if (state != null)
{
try
{
IWorkflowInfo workflowInfo= workItemCommon.findWorkflowInfo(workItem, null);
if (workflowInfo.stateGroupContains(IWorkflowInfo.CLOSED_STATES, state))
{
return true;
}
}
catch (TeamRepositoryException e)
{
return false;
}
}
}
return false;
}
private static void addAdvisorInfo(int severity, String summary, String description, IAdvisorInfoCollector collector)
{
if (collector != null)
{
IAdvisorInfo message =
collector.createProblemInfo(summary,
description,
PROBLEM_TYPE);
message.setSeverity(severity);
collector.addInfo(message);
}
}
}
Accepted answer
Hello,
The process runtime (that runs your operation advisor) is not able to find the link service because it has not been loaded. It has not been loaded because it has not been specificed as a required service. To specify it as a required service, you can add an extensionService element in the plugin.xml file and list the service in the prerequisites section.
Here is an example of a required service in an operation advisor that I pulled from a test plugin:
Martha
Jazz Developer, Process Component
The process runtime (that runs your operation advisor) is not able to find the link service because it has not been loaded. It has not been loaded because it has not been specificed as a required service. To specify it as a required service, you can add an extensionService element in the plugin.xml file and list the service in the prerequisites section.
Here is an example of a required service in an operation advisor that I pulled from a test plugin:
<operationAdvisor>
<description>
Advisor which requires that an example item's description has changed
</description>
<extensionService>
<prerequisites>
<requiredService>
</requiredService>
</prerequisites>
</extensionService>
</operationAdvisor>
Martha
Jazz Developer, Process Component
Some additional information regarding the problem I have posted above.
The plugin.xml file:
+?xml version="1.0" encoding="UTF-8"?>
+?eclipse version="3.4"?>
+plugin>
+extension
point="com.ibm.team.process.service.operationAdvisors">
+operationAdvisor
class="helloworldadvisor.HelloWorldProhibitSave"
id="HelloWorldAdvisor.prohibitSave"
name="Prohibit Save (Hello World Advisor)"
operationId="com.ibm.team.workitem.operation.workItemSave">
+/operationAdvisor>
+/extension>
+/plugin>
A screen shot of the dependencies listed in the RTC plugin project.
http://dl.dropbox.com/u/2766268/RTC%20Advisor%20Problem%201.png
<operationAdvisor>
<description>
Advisor which requires that an example item's description has changed
</description>
<extensionService>
<prerequisites>
<requiredService>
</requiredService>
</prerequisites>
</extensionService>
</operationAdvisor>
4 other answers
Some additional information regarding the problem I have posted above.
The plugin.xml file:
A screen shot of the dependencies listed in the RTC plugin project.
http://dl.dropbox.com/u/2766268/RTC%20Advisor%20Problem%201.png
The plugin.xml file:
+?xml version="1.0" encoding="UTF-8"?>
+?eclipse version="3.4"?>
+plugin>
+extension
point="com.ibm.team.process.service.operationAdvisors">
+operationAdvisor
class="helloworldadvisor.HelloWorldProhibitSave"
id="HelloWorldAdvisor.prohibitSave"
name="Prohibit Save (Hello World Advisor)"
operationId="com.ibm.team.workitem.operation.workItemSave">
+/operationAdvisor>
+/extension>
+/plugin>
A screen shot of the dependencies listed in the RTC plugin project.
http://dl.dropbox.com/u/2766268/RTC%20Advisor%20Problem%201.png
Hello,
In case I would have to support the functionnalities that are actually offered in a custom Clearquest schema (similar to the Former Analyst CQ schema) within RTC, I know we can create custom workitems, custom workflows and even _if i'm correct_ customized edition views.
But what arethe things that you cannot do today in RTC 3.0.1 regarding the defintion of a workflow for a custom work item?
Regards,
Olivier
In case I would have to support the functionnalities that are actually offered in a custom Clearquest schema (similar to the Former Analyst CQ schema) within RTC, I know we can create custom workitems, custom workflows and even _if i'm correct_ customized edition views.
But what arethe things that you cannot do today in RTC 3.0.1 regarding the defintion of a workflow for a custom work item?
Regards,
Olivier