Recently, a customer wanted to make attributes required and read only in a way the built in operational behavior does not support. So I tried to find out if there would be a way to achieve this by an extension. After struggling for some time, I finally found a way and want to share this with the community.
Update: see A Custom Condition to Make Attributes Required or Read-Only by Role Version 2 for some more tricks and information.
The Requirement
The requirement was,
- A user can have multiple roles
- Attributes are required or read only for a role in a certain state
- For a user all roles shall be evaluated and the attribute be required or read only if any of the roles the user has, specifies so
So the intended behavior was more like permissions work in RTC, accumulate over all roles.
The built in RTC mechanisms for required and read only attributes are based on operational behavior. Built in advisors can be configured to provide the information and behavior.
You can configure operational behavior for each role, in this example it is for the default role Everyone. However, the operational behavior in RTC does only look for the first configured operational behavior for the operation that is configured for a role the user has, as described in Process behavior lookup in Rational Team Concert 2.0. This is which is still valid for later versions of RTC.
A user has one (every user has the Everyone role) or more roles configured if he is member of a project or team area. The roles have an order, from top to bottom. The first configured operational behavior for the first role in that order that is found in the context of an operation will be executed. Only that first found operational behavior will be executed.
The idea behind this concept is, that it is possible to overwrite the operational behavior by having specific roles in a specific order. It is, for example, possible to have configured that users with the role Everyone need to provide several required attributes to save a work item and several attributes can be read only. But the Team Lead may have a lot less required attributes and no read only attributes, because the operational behavior is specified in a different way for the Team Lead role.
This also means, if the check box “Preconditions and follow-up actions are configured for this operation” is checked for a role and no preconditions are configured, RTC will do nothing, if the user has that role, even if a lot of preconditions are configured for the role Everyone. RTC will find the specification for that role and as there is nothing configured assume there is no operation behavior needed for the role.
It also means, if operational behavior is specified for all roles, only the operation behavior of the primary role the user has in the context, is executed.
The customer wanted a behavior that was different. Assume role1 and role2 exist. A work item attribute is specified to be read only for role1 but not read only for role2. The attribute shall be read only for all users that have role2 assigned, regardless of the order of the roles.
This is, again, more like permissions as described in Process permissions lookup in Rational Team Concert 2.0 where if one role a user has, has the permission, the user has this permission.
How Does the RTC Code Work?
I looked at how this is implemented in RTC by looking into the SDK in the hope to find a way to extend it somehow. It is pretty easy to find the code of the advisors/preconditions shipped with RTC. It took me a while to figure out what is going on in the code.
One thing that had bothered me for a while became understandable in the process: Operation behavior is run after the save button is pressed. How can operational behavior have any impact on the UI before the button is pressed? How can the UI show attributes as read-only or as required before the operation is performed?
Well, it turns out, that the built in advisors have a static part, that reads the configuration. The UI knows the built in advisors and calls this part to get the configuration data in order to require attributes or make them read only. Mystery solved.
This, of course means there is no way to create your own advisor/precondition to extend RTC to work with different rules and the UI showing behaving like with the built in advisors. The UI does not know that it needs to get the custom configuration and that’s it. It is still possible to prevent a save, but the UI won’t provide any information up front.
At this point I was very close to giving up. The issue had passed a lot of smart people’s desks at that time, including mine – 5 times at least. Why should I find a solution if no one else had the slightest idea?
The Solution
Well, when looking at the code, I realized some other built in operation behavior was wired up there as well. Code for the advisors to control required and read only attributes for conditions.
This turned out to be the approach that allowed to implement the requirement. Create a custom condition that allows to configure the condition advisors in a way to provide the functionality as requested.
One important issue that became apparent in the process of creating this solution is that conditions are different from all the other attribute customization providers. This almost led to me failing in finding a solution to implement this.
Conditions need to be instantiated like all the other providers but
- Condition instances are not configured at the attribute
- Conditions are only configured in the aforementioned preconditions
- Conditions don’t get the information about the attribute they are configured for
My initial idea was to somehow configure the condition’s additional script parameters in the process XML with information about attribute ID’s, for which roles in which states the condition returns false. This does not work. Instead the condition gets information for which state Id for which work item category, which roles are relevant. This way one condition can handle all cases as we will see in the following sections.
Solution Summary
The condition, lets call it User Role for Type and State Condition is a Java based extension for the Eclipse client and the RTC server. It allows configuring roles mapped to work item type categories and states.
The condition checks if the current work items category and state has roles configured. If roles are found, and the user has any of the roles, the condition returns true, false otherwise.
This condition can be configured and be used to make work item attributes read-only or required for a work item type category in a specific state based on the roles a user has in this context.
License and Download
The post contains published code, so our lawyers reminded me to state that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!
The code can be downloaded from DropBox here. Please note, there might be restrictions to access DropBox and the code in your company or download location.
Just Starting With Extending RTC?
If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.
You should be able to use the code attached to this post in the development environment you set up in the Rational Team Concert Extensions Workshop and get your own extensions or automation working there as well.
In this context, please also consider to at least read through the Process Enactment Workshop for the Rational solution for Collaborative Lifecycle Management lab 4 and lab 5 to understand how attribute customization works.
Import The Code
Use the Eclipse importer to import existing projects into the workspace from an archive file.
Browse for the archive.
Select all projects and press finish. The code now shws up in your Eclipse workspace.
How The Code Works
The code comes in four projects.
com.ibm.js.team.workitem.attribute.user.role.condition.providers: The main project for the extension. It contains all the code that is needed and defines the plugin.xml.
com.ibm.js.team.workitem.attribute.user.role.condition.providers.feature: The feature project needed to be able to deploy the code.
com.ibm.js.team.workitem.attribute.user.role.condition.providers.updatesite: The update site needed to generate the code for deployment. This project output is also used to deploy the extension in RTC Eclipse clients.
com.ibm.js.team.workitem.attribute.user.role.condition.providers.serverdeploy: A special project to help deploying the code on RTC servers.
The structure of the main project looks like this.
The source code is provided in four classes. The majority of the code is implemented by the class AbstractUserRoleTypeAndStateConditionProvider. It implements all of the behavior needed.
The only piece missing in the code is the part that provides the process areas (project and team areas) used to look for the roles the user has. It is possible to use different approaches to configure this in RTC and based on how this is configured in RTC there are different possible approaches you want to use to get that information. So this is left abstract to be implemented in an extending class.
Possible strategies are:
- Look for the roles a user has in the team area that owns the work item
- Look for the roles a user has in the project area
- Look for all the roles a user has across the hierarchy of the area that owns the work item up to the project area
There might be other strategies, dependent on the context this is used in. It is possible to extend the abstract class and to provide the process areas to look into.
The class
- ProcessAreaHierarchyUserRoleTypeAndStateConditionProvider implements strategy 3
- ProcessAreaUserRoleTypeAndStateConditionProvider implements strategy 1
- ProjectAreaUserRoleTypeAndStateConditionProvider implements strategy 2
Lets have a quick look at the code provided in the abstract class.it implements the method matches required by the Interface ICondition that is needed to be implemented for a condition.
/* (non-Javadoc) * @see com.ibm.team.workitem.common.internal.attributeValueProviders.ICondition#matches(com.ibm.team.workitem.common.model.IWorkItem, com.ibm.team.workitem.common.IWorkItemCommon, com.ibm.team.workitem.common.internal.attributeValueProviders.IConfiguration, org.eclipse.core.runtime.IProgressMonitor) */ @Override public boolean matches(IWorkItem workItem, IWorkItemCommon workItemCommon, IConfiguration configuration, IProgressMonitor monitor) throws TeamRepositoryException { // Get the work item type category of the work item to determine if this // condition is configured for it IWorkItemType wiType = workItemCommon.findWorkItemType( workItem.getProjectArea(), workItem.getWorkItemType(), monitor); String typeCategory = wiType.getCategory(); // Get the workflow action String actionId = configuration.getProviderContext() .getWorkflowAction(); // Get the work item state. // The state could be the current one, or it could be determined // by the workflow action that is currently selected String wiState = findTargetStateId(workItem, actionId, workItemCommon, monitor); // Find the roles that are configured for the work item type (by type // category) for the work item state Set roles = getRoleConfiguration(typeCategory, wiState, configuration); if (null == roles) { // No Roles found, we can exit. return false; } // Get the roles the contributor has in this context Collection contributorRoles = getContributorRoles(workItem, workItemCommon, monitor); // Return true, if the contributor has any of the configured roles return hasMatchingRole(roles, contributorRoles); }
This method first looks up the work item type and from that the work item type category. We use the type category, because all work item types of the same category have the same attributes and workflow. It would be possible to use the type directly, if needed.
Then it looks up the current workflow action from the provider context. As described in the AttributeCustomization wiki entry, conditions get the currently selected workflow action. The condition needs this to determine if a state change is about to happen and to get the roles configured for that state and not the current one. The state that is relevant for this operation is looked up.
The method then uses the work item type category, the relevant state and the configuration to determine the roles that are configured for this context. If there are no roles valid for this context the condition can end and return false.
If there are roles configured for this situation, the method gets the roles of the user trying to perform the operation.
The final check is, if the current user has any of the roles configured for this context.
Lets look at how finding the state of the work item works in findTargetStateId(). The code can be found in the SDK in the context of the preconditions.
/** * Find the target state of the work item for the condition. * The target state is the current state if there is no workflow action selected * If there is a workflow action selected, the target state is the state * the action results in. * * @param workItem * @param actionId * @param workItemCommon * @param monitor * @return the state ID (or null if there is no identifiable state) * @throws TeamRepositoryException */ private static String findTargetStateId(IWorkItem workItem, String actionId, IWorkItemCommon workItemCommon, IProgressMonitor monitor) throws TeamRepositoryException { Identifier state = workItem.getState2(); IWorkflowInfo wfInfo = workItemCommon.findWorkflowInfo(workItem, monitor); if (state == null && actionId == null && wfInfo != null) { actionId = wfInfo.getStartActionId() == null ? null : wfInfo .getStartActionId().getStringIdentifier(); } if (wfInfo != null && state != null) { if (!Arrays.asList(wfInfo.getAllStateIds()).contains(state)) { actionId = wfInfo.getStartActionId() == null ? null : wfInfo .getStartActionId().getStringIdentifier(); } } if (actionId != null && wfInfo != null) { state = wfInfo.getActionResultState(Identifier.create( IWorkflowAction.class, actionId)); if (state == null) { actionId = wfInfo.getStartActionId() == null ? null : wfInfo .getStartActionId().getStringIdentifier(); if (actionId != null) { state = wfInfo.getActionResultState(Identifier.create( IWorkflowAction.class, actionId)); } } } // This is code that addresses a change in the process, // where the state of a work item can have only a number // Make sure the number is modified to reflect the state ID if (state != null) { String stateId = state.getStringIdentifier(); try { Integer.parseInt(stateId); stateId = "s" + stateId;//$NON-NLS-1$ } catch (NumberFormatException e) { } return stateId; } return null; }
The code gets the work item state and the workflow information first. If there is no state and no action, then the work item is new and the action is the start action.
Then it looks at the case where there is a state and a work flow action, if it can’t find the current state in the workflow, there was a type change and the action is the start action (or none).
With the action identified, it calculates the target state. If there is none, the current state remains.
Finally there is a handling of the state ID’s. In some cases, for historical reasons, only a number is returned and not a sate id, The last bit of the code makes a proper state ID from the number, if needed.
The correct target state of the work item is returned at the end.
Another interesting part is to get the configuration for the roles from the process configuration done in getRoleConfiguration().
/** * Get the roles that are configured for the work item category and current target state * * @param typeCategory * @param wiState * @param configuration * @return returns a set of roles that are configured for the * work item category and state, or null, if there is not matching configuration */ private Set getRoleConfiguration(String typeCategory, String wiState, IConfiguration configuration) { List workflowConfigurations = configuration .getChildren(CONFIGURATION_ELEMENT_WORKFLOW_PROPERTIES); if (null != workflowConfigurations) { // We got a configuration // For all configuration elements for (IConfiguration workflowConfiguration : workflowConfigurations) { // Get the workitem state for this configuration element String foundStateID = workflowConfiguration .getString(CONFIGURATION_WORKFLOW_PROPERTY_ATTRIBUTE_STATE_ID); // Get the work item category for this configuration element String foundWorkflowCategory = workflowConfiguration .getString(CONFIGURATION_WORKFLOW_PROPERTY_ATTRIBUTE_WORK_ITEM_TYPE_CATEGORY); // If the configuration element applies to the current work item // state and category, get the roles that are configured if (foundStateID != null && foundWorkflowCategory != null && foundWorkflowCategory.equals(typeCategory) && foundStateID.equals(wiState)) { return getRoles(workflowConfiguration); } } } return null; }
The conditions can be configured in the process configuration source as described here. The code reads the configuration data in the process.xml. It tries to find a configuration for the work item category and the state in the configuration. If one is found, it gets all roles specified and returns them.
The method getRoles() looks as below:
/** * Get the roles configured for this configuration element * * @param workflowConfiguration * @return the roles found */ private Set getRoles(IConfiguration workflowConfiguration) { Set roles = new HashSet(); List roleConfigurations = workflowConfiguration .getChildren(CONFIGURATION_ELEMENT_ROLE); for (IConfiguration roleConfiguration : roleConfigurations) { roles.add(roleConfiguration.getString(CONFIGURATION_ATTRIBUTE_ROLE_ID)); } return roles; }
It basically also reads the next level in the process configuration XML to get the configured role ID’s.
When designing the condition the following structure for the configuration was chosen.
Basically provide the workflowProperties for the workitem type category and the state. Underneath provide the ID’s for the roles the condition should trigger.
As an example of the configuration in the process XML:
The last step is to get the roles of the user that tries to perform the operation. This is done in getContributorRoles().
/** * Get the roles for a contributor * * @param processArea * @param user * @param workItemCommon * @param monitor * @return * @throws TeamRepositoryException */ private Collection getContributorRoles(IWorkItem workItem, IWorkItemCommon workItemCommon, IProgressMonitor monitor) throws TeamRepositoryException { Collection roles = new HashSet(); // Get Current User - we will check for the roles this user has IContributorHandle user = workItemCommon.getAuditableCommon().getUser(); // Get the relevant process area(s) to look for the role Collection processAreas = getProcessAreas(workItem, workItemCommon, monitor); // Iterate the relevant process areas for (IProcessAreaHandle processAreaHandle : processAreas) { // Resolve the process area IAuditableCommonProcess auditableCommonProcess = workItemCommon .getAuditableCommon() .getProcess(processAreaHandle, monitor); IProcessArea processArea = (IProcessArea) workItemCommon .getAuditableCommon().resolveAuditable(processAreaHandle, ItemProfile.PROCESS_AREA_DEFAULT, monitor); // get the roles and add them to the list of roles the contributor has roles.addAll(auditableCommonProcess.getContributorRoles(user, processArea, monitor)); } return roles; }
The method gets the current user. Then it calls the abstract method getProcessAreas() to get the process areas to look for roles. It then iterates the process areas retrieved, gets the process and the roles of the user.
The method hasMatchingRole() just iterates the roles found and returns true, if the user has a role that is configured in the configuration for the given work item category and the state the work item has in this context.
/** * Check if the contributor has one of the configured roles. * * @param roles * @param contributorRoles * @return true if the contributor has a role that is found in the configuration */ private boolean hasMatchingRole(Set roles, Collection contributorRoles) { for (IRole aRole : contributorRoles) { if (roles.contains(aRole.getId())) { // The user has a role that was relevant for this configuration return true; } } return false; }
The classes that implement the AbstractUserRoleTypeAndStateConditionProvider basically have to implement which process areas to look at and to return them in getProcessAreas().
The version below is the most complex one, that iterates the whole hierarchy implemented in the class ProcessAreaHierarchyUserRoleTypeAndStateConditionProvider.
/*** * * Get the list of process areas to look up the roles for the contributor * Start with the process area a work item is filed against * and iterate the process area hierarchy up to the project area. * * All found process areas are added to the search list. * */ /*(non-Javadoc) * @see com.ibm.js.team.workitem.attribute.roletypestate.condition.providers.AbstractUserRoleTypeAndStateConditionProvider#getProcessAreas(com.ibm.team.workitem.common.model.IWorkItem, com.ibm.team.workitem.common.IWorkItemCommon, org.eclipse.core.runtime.IProgressMonitor) */ @Override Collection getProcessAreas(IWorkItem workItem, IWorkItemCommon workItemCommon, IProgressMonitor monitor) throws TeamRepositoryException { // Get the project area HashSet processAreas = new HashSet(); // Resolve with full data to get the hierarchy IProjectArea projectArea = (IProjectArea) workItemCommon .getAuditableCommon().resolveAuditable(workItem.getProjectArea(), ItemProfile.PROJECT_AREA_FULL, monitor); // Get the hierarchy to be able to find the process area parents ITeamAreaHierarchy hierarchy = projectArea.getTeamAreaHierarchy(); // Start with the process area the work item is filed against IProcessAreaHandle processAreaHandle = workItemCommon.findProcessArea(workItem, monitor); do{ // If this is a team area, add it and look for the parent area if (processAreaHandle instanceof ITeamAreaHandle) { processAreas.add(processAreaHandle); try { // Try to get the parent process area processAreaHandle = hierarchy.getParent((ITeamAreaHandle)processAreaHandle); } catch (TeamAreaHierarchyException e) { // this should not happen, if it does, stop the loop return processAreas; } } else if (processAreaHandle instanceof IProjectAreaHandle) { // If the area is the project area, we are done processAreas.add(processAreaHandle); return processAreas; } } while (processAreaHandle!=null); return processAreas; }
It basically gets the project area of the work item and looks up the ITeamAreaHierarchy for it. Then it gets the process area that owns the work item. If that is a team area and not the project area, it adds the team area to the list and then tries the same with its patent process area. If the process area is a project area, it is added to the list and the method is done.
The Plugin.XML
The plugin.XML basically defines the value providers that are available as well as the component for them.
The condition providers are configured as shown below.
Before deploying, the code has to be built. This is done in the project com.ibm.js.team.workitem.attribute.user.role.condition.providers.updatesite
Make sure the update site project is empty like below
Delete any other files and folders visible besides the .project file and the site.xml, e.g. Jar-files and folders like plugins and features.
Open the site.xml and press Build All in the editor.
The update site project now has new files and folders.
These files will be used to deploy the extension to the server and later to deploy the extension on the RTC Eclipse client.
Deploy on the RTC CCM Server
There is a special project that was artificially created to help with deploying on the server. The project com.ibm.js.team.workitem.attribute.user.role.condition.providers.serverdeploy contains a folder structure that resembles the structure in the configuration folder of the server. The folder provision_profiles/ contains the provisioning file js_user_role_condition_provider.ini that contains the information needed to deploy the extension on the server. It also contains the reference to the folder site/js_user_role_condition_provider which is reflected in the project structure as well. This folder needs to contain the built features and plugins. By setting this up this way, it is relatively easy to successfully deploy the extension.
After building, copy the folders features, plugins and the file site.xml from the project com.ibm.js.team.workitem.attribute.user.role.condition.providers.updatesite into the folder sites/js_user_role_condition_provider in the project com.ibm.js.team.workitem.attribute.user.role.condition.providers.serverdeploy as displayed below.
Open the conf/ccm folder for your deployed server (Try this on a test server first). Open the folder \JazzTeamServer\server\conf\ccm like shown below.
In the project com.ibm.js.team.workitem.attribute.user.role.condition.providers.serverdeploy, select the folders provision_profiles and sites. Then select Copy.
In the folder \JazzTeamServer\server\conf\ccm paste the folders and files you just copied. Acknowledge overwriting folders (and files if the extension has been deployed).
Request a server reset and restart the server. See Is The Extension Deployed? How Can I Redeploy? for details.
Check if the server Extension is deployed as described in Is The Extension Deployed? How Can I Redeploy? Search for the component com.ibm.js.team.workitem.attribute.user.role.condition.providers.component.
The condition provider is now deployed on your CCM server.
Deploy on the RTC Eclipse Client
The condition needs to be installed on an Eclipse client to be configured. It also needs to be installed on all Eclipse Clients that are used by users that have to use this condition.
It is possible to install this in an Eclipse client (installed from a zip file) and ship the Eclipse client with the extension installed by zipping it up again and providing the zip file.
For users that use the Web UI, the Condition works as soon as it is set up in the process.
To install the extension on an Eclipse client start Eclipse and select the menu Help>Install New Software…
In the install wizard select add.
Then select Local and browse to the folder with your project com.ibm.js.team.workitem.attribute.user.role.condition.providers.updatesite
Select the User Role Condition Providers Feature, you might have to deselect the check boxes like below to see it.
Press next and follow the wizard to install the extension. Restart the client.
Configure the Project
Open an Eclipse client that has the condition installed to configure it. Open the project area to configure its process.
Create Conditions for the Attributes
Open the Process Configuration. Select Process Configuration>Project Configuration>Configuration Data>Work Items>Attribute Customization.
For each attribute that needs to be read only or required, use the Add button to add a new condition.
Provide a name for the condition. The best approach is to name the condition in a naming schema that contains the usage of the condition and the attribute name. As an example name it Read_Only_AttributeName or Required_AttributeName. the reason will become apparent later. It basically helps finding it later to configure it in the operational behavior and the process XML.
You should now see the providers that you deployed in addition to Java Script. Select the provider that works best for you.
Please note, if you have groups of attributes that behave the same for all role configurations, you can create one condition for this group, instead of creating it for only one attribute.
After you created your configurations the Attribute Customization section should look as below.
Configure the Operational Behavior
After creating the conditions needed, the next step is to activate the conditions for the attributes in the operational behavior.
Select Process Configuration>Team Configuration>Operation Behavior.
Select the “Everyone” role and add the preconditions Required Attributes For Condition and Read Only Attributes For Condition.
Please note: if you want to configure this for another role, you have to configure the conditions for that role as well. How to do this efficiently is described below.
For each condition you created add a configuration for the related precondition. Select the condition and the attribute that the condition governs.
If you have groups of attributes that behave the same across all workflows and roles, you can use one condition for that group and select all affected attributes here.
The image below shows an example configuration.
Configure the Conditions in the Process Configuration Source
The Conditions don’t have any configuration for workflow states, work item categories and related roles yet. This needs to be done last. To configure the conditions it is necessary to add information to the process configuration source.
Locate the conditions in the process configuration source e.g. by searching for the name of a condition. The conditions are all in one block.
For each condition, remove the closing /at the end of the condition element and add a new ending tag .
The data should now look like the image below and there should be no errors. If there are errors, correct your XML.
Now add the type, state and role configuration for each condition.
You can configure for each condition for which work item type category (work item types with the same workflow), for which state, which roles should match the condition.
Save your work!
Test your work
To test, create a work item and move it through the workflow using user ID’s with role configurations that match your expectation. Make sure the user has roles that match the condition configuration.
In this case the Attribute Filed Against is required due to the roles of the user and the description is read only in the state. Please note, that the work item is not yet initialized, but the target state is new. The section below explains the format and how to retrieve the data.
Retrieving the Configuration Data
To configure the condition, it is necessary to get the data to do the configuration. This section describes how to get the data.
The State ID’s and the Work Item Type categories as well as the Role ID’s can be retrieved from the process template.
The work item type category can be found in the web UI as well as in the Eclipse UI.
The work item type category here is: “com.ibm.team.workitem.workItemType“.
To find the workflow state names use the Eclipse client and search the process configuration source for the workflow name e.g. Defect Workflow in this case. Scroll down to find the state elements.
Look up the state ID’s for the states and document them. This is a one-time action and only needs to be maintained if you change workflows and add states.
The state New has the identifier “s1”, the state In Progress has id=”S2” etc.
To find the role Identifiers, open the project area or team area and select the roles.
The role test1 has the identifier “test1” the role Product Owner has the identifier “Product Owner”.
The role “Everyone” has the identifier “default”.
The configuration below configures the condition to return true for
- a work item of this type category (a defect) in the New state “s1” for the role “test1”.
- a work item of this type category (a defect) in the Resolved state “s3” for the role “test1”.
- a work item of this type category (a defect) in the In Progress state “s3” for the roles “test1”, “test2” and Everyone.
See another more complex example below.
Configuring the Operational Behavior for Multiple Roles
Operational behavior still works as explained in Process behavior lookup in Rational Team Concert 2.0. If it is necessary to configure the operational behavior for multiple roles but to make sure the Required and Read Only Attributes work the same as in the configuration for the Everyone role, this can be easily achieved.
Configure the other role(s).
When configuring the operational behavior name the precondition with the role included. For example Required Attributes For Condition Everyone.
Configure the operational behavior for the new role including the Role Name but don’t configure anything. For example name it Required Attributes For Condition Role1.
Search for the configuration for the configured role in the process configuration source.
Copy the configuration details into a file. The interesting parts are the sections and <readOnlyAttributes….> .
Now search for the configuration for the new role the same way. Copy the XML with the configuration for the Required Attributes into the operational behavior configuration. Copy the XML with the configuration for the Read-Only Attributes into the operational behavior configuration.
Save your work!
Since the conditions are configured globally you have essentially cloned the configuration for the other role.
Summary
Using a custom condition and the out of the box operational behavior for Required Attributes For Condition and Read-Only Attributes For Condition, allows to achieve the required behavior.
Keep in mind this is by no means production code. You might want to do more testing.
As always I hope this helps someone out there to get their job done more efficient.
Hello Ralph,
In a scenario we have a condition where the FoundIn for Everone role for state s1 is configured read-only, now for a new role eg: tester we have cloned the everyone role configuration, now but for this role the attribute FoundIn is mandatory in state s1.
now when this operation behaviour is configured for the tester role on top of the cloned everyone configuration it is noticed that the found attribute is becoming both read-only as well as mandatory.
so do we have to fine tune these conflict manually or there could be a possibility to overcome this programmatically?
Thanks in Advance,
Abhishek Kumar
Are you talking about the extension described in the article?
If so, the behavior of the condition is designed to accumulate rules for all roles a user has.
So, if you construct role models where the user end up having required attributes being read only, you will have to reconsider your role model or create an extension that has other rules.
I have answered this new requirement in https://rsjazz.wordpress.com/2015/08/07/a-custom-condition-to-make-attributes-required-or-read-only-by-role-version-2/
Using this function, we restrict modification to the Work Item attributes by state and user?
By user role, type and state.
Hi Ralph,
Thanks for your reply. Your information is very useful for RTC developers.
Is it possible to restrict modification to the work item attributes by state and user?
Naresh,
you can use the same approach for many different scenarios, provided you have the information in the condition. Instead of looking up the roles, you could in this case look up the user ID. In the configuration you would then e.g. store the ID of users that can modify or can not modify.
I don’t think that this is really scalable and using some grouping mechanism like role is more scalable.
It would also be possible to have a mix e.g. be able to add a configuration element with user ID’s.
Thanks for your information, Ralph. I will try and test it.
Also see https://rsjazz.wordpress.com/2015/08/07/a-custom-condition-to-make-attributes-required-or-read-only-by-role-version-2/ for more information.
Please also check the built in permissions as well as the required and read only attributes by type and state behavior. Another approach – without UI help can be found here: https://rsjazz.wordpress.com/2014/05/26/only-owner-can-close-workitem-advisor/ . As described in the second version of this post, conditions are the only real way to have the UI show the rules.
Hi Ralph,
Am new to the RTC environment, I want to develop one plugin like this.
Now I done whatever the steps given in this article but i don’t know how to test this plugin?
can you please guide me to test this plugin?
And how its working from client side because I deployed the plugin in server and restarted the server also, after that i gave the local path of the “updated site” in “Install New Software”.
Follow the section “Just Starting With Extending RTC?” and do the extensions workshop mentioned there. Then use the debugging capabilites explained there.
If you rebuild the update site, you can use that in the client and install the extension in the client like any other Eclipse extension.
This is described here: https://rsjazz.wordpress.com/2015/06/19/a-custom-condition-to-make-attributes-required-or-read-only-by-role/
Ralph, what is the use of Create Conditions for the Attributes?
Using this scenario and source code I tried to create work item, but it throws 2 errors are
1. An unhandled exception occurred during “Required Attributes For Condition”.
2. An unhandled exception occurred during “Read-Only Attributes For Condition”.
can you please explain why we need to create dynamically the condition for the attributes?
I essentially have no time for the next two weeks to look at this. Nor to moderate and answer questions.
Why don’t you find out and tell us?
As a sidenote, there is no condition dynamically created. The condition just calls the other configured operational behavior – as explained in the article.
Hi Ralph, Is it need to create the Pre-Conditions & Followup actions in client side for server side (deployed in server) plugin?
I think it is needed to deploy them in the client to
* be able to configure them in the Eclipse client
* have them available if the work item is changed in the Eclipse client
I have redeployed the plugin in the server. In the Provision Status console I can able to see the plugin “This feature is being installed: “Test_1.0.0.201509041706”. but unfortunately the same plugin is not listed in the component status console.
I followed the steps “https://rsjazz.wordpress.com/2014/06/12/is-the-extension-deployed-how-can-i-redeploy/” given in this document also.
Please share any information if you know about this.
I have shared what I can and I usually get my stuff deployed. Remove all the deployed files related to the extension. Restart the server and request a server reset.
Restart the server, check the deployment status.
The rebuild the update site and redeploy. In Eclipse Clients you might have to restart Eclipse with -clean. In addition, try if you see the condition in the Eclipse client (where you deployed it) and can configure it.
I assume you have tested this with Jetty and a debug Eclipse before you tried to deploy it and it works there.
I have gone through many articles, i found that many articles implements the match() method as entry point to the server side plugin.
and also many articles implements run() method as the entry point to the server side plugin.
Can anybody please share the documentation about these methods.i am getting confused using these methods.
Please share server side API documentation .
I have gone through many articles regarding the server side API development. As per some article, run() method is the entry point for plugin .
refer: https://rsjazz.wordpress.com/2014/05/26/only-owner-can-close-workitem-advisor/
and also the article like:
https://rsjazz.wordpress.com/2015/06/19/a-custom-condition-to-make-attributes-required-or-read-only-by-role/
matches() method is the entry point for the plugin.
Kindly share some idea’s regarding the run method and match method.Also please share the server side API documentation.
The extension point defines the interface that is needed to be implemented.
I have shared many examples already. This is my personal blog and it is not meant to be an online service portal. You can enable yourself with the examples.
Am also struck up in this place, and I could not find any examples regarding that.
I tried to call the matches() method from run() method and IWorkItem, IWorkItemCommon,
IConfiguration , IProgressMonitor these are the parameters for the matches().
From run() i get the IWorkItem, IWorkItemCommon,IProgressMonitor but i could not able to get the Iconfiguration for matches().
Can you please share information regarding Iconfiguration?
Can you please share your suggestions is this flow is correct or not?
What you try here is beyond me.
As described in the post, the code is for an Eclipse/RTC Extension plug-in and the interface provided is used by the extension point. If you want to use parts of the code in a plain java application, you have to copy it into your own project and provide the necessary information and client libraries to it.
See http://www.ibm.com/developerworks/library/os-eclipse-plugindev1/ to understand what plugins are and how they work. There are many other sources bout this topic on the internet.
Thanks for your documents Ralph.
1. I tried what are the steps you given in this article for deploy the plugin and test the plugin.
2. I deployed the plugin in server and its also running.
3. I gave the preconditions as per your document and I tried to create one WorkItem but I am getting “Exception Checking PreCondition” error for “Required Attributes for Conditions & Read-Only Attributes for conditions”.
4. In the mean time, I checked the CCM log file and getting the following error “ERROR com.ibm.team.process.common java.lang.NullPointerException”.
5. matches() is calling.
How to resolve the “Exception Checking PreCondition” issue. Anybody knows please help me to resolve this problem.
@ Shiva: Please read the document clearly.
I don’t know what is going wrong. I would suggest to debug this in your development environment.
Thanks Ralph. Its working.
So what was the problem?
Ralph. The problem was “Required Attributes For Condition & Read-Only Attributes For Condition” are did not properly configured. Thanks for your help Ralph.
I tried to get the state IDs(list out in dropdown only) details from dropdown-status attribute but i can able to the current stateid only using getState2 method.
If its possible to get/fetch the last saved state details or get the states details from status attribute?
This is not related to the post above and you should ask these questions in the Jazz forum.
It is posible, btw, to access the historical states of the work item and to get this information, but it is not trivial
Thanks Ralph.
I am trying to get/read the current state ID from status attributes while loading the page/refresh the status attributes in RTC.
I tried to find out the state id but I got the state id details when choose the state in status attribute only using matches() method-(entry method).
So please help me, how to get the state ID details while loading the page or refresh the status attributes.
I can’t able to post the comments in forums using my machine. There are some restrictions.
I am sorry, but I can’t understand what you are asking for.
In the code below, the current state of the work item in the context of the condition is calculated in findTargetStateId() and it basically uses the current state or the state the work item would be in, in case the user has selected a workflow action/state change.
For example 5 states(State1, state2, state3, state4 and state5) in an one WorkItem, I have an access for state1, state3 only.
I configure the roles in condition of processconfigurationsource.xml.
Steps:-
1. I created one workitem, so now my current state is New(state1).
2. I have access in state1 and edited some values in comments attributes and choose the “state2 in Status Attribute” and I tried to save the workitem. But the status attribute is going to readonly mode when I am selecting the state 2 in Status Attribute. I have access in state1 and i want to move my state1 to state2 but its not working.
Clarifications:-
1. Why its not allows me to save the workitem in State1(I have access) –> State2(I dont have access) condition?
2. As per my thought its restricts the attributes only when I have no access in the current state only.
Please clarify me Ralph.
The condition – as clearly visible in the code – calculates the state of the work item from its current state and the selected workflow action.
If you have configured attributes as read only and enter them and then select a workflow action, the effective state of the work item is the new state which changes the required and mandatory attributes.
1. The process you are trying to implement is of the type that is overly complex and prone to drive the users crazy. Rethink your process specification.
2. Your understanding about how RTC process customization works is too limited. Get payed consulting for a process review and help to implement it, if at all possible.
Thanks for your information Ralph & Irfhan, I have also same clarification.
I don’t have access in state2, so should not permit any modification or should not allows to change from state 2 to any other state.
For this option I tried to make the status attribute(list of states) as readonly.
1. Chosen the state from State1 to State2 and click the save button. But I am getting Attribute ‘Status’ is not modifiable. But It should be allows here and restricts or read only the status attributes in State2.
Sorry for confuses.
I plan to restrict some attributes depends upon the state and user role.
So I define the access for state1 and restrict the access for state2(For the attributes are Priority, Description and status).
1. Now am in state1, in this state i modify the priority, description and status attributes and click the save button, but its shows the following warning message”Attribute ‘Status’ is not modifiable. The status attribute is not modifiable(work item 107)”.
2. I restricts the attributes(riority, description and status) in state2(depends upon the roles configure in the Process.xml). But why it’s coming when i change the state from current state to target state.
Please clarify me.
It does not make any sense to restrict access to the state attribute. If you do so, and the user can’t write the state that would be reached after a workflow action is selected, this works as designed in the condition.
Again, consider to get some process consulting.
Hi Ralph,
I have developed one custom plugin like this, I can able to make the attributes as read-only for a role in particular state. This function is working in WebUI but in RTC Eclipse not working like that.
Can you please suggest any idea to rectify that.
Have you deployed the provider to the Eclipse client? As far as I can tell, it needs to be available in the Eclipse client for it to work.
Ralph,
Yes, deployed the provider to the Eclipse Client and below listed the steps I done it in client.
1. Installed the “Update Site” folder in the RTC Eclipse client.
2. We defined the Preconditions & Workflow configurations in the Project area.
3. I checked in WebUI, RTC WebUI its working but its not working in RTC Eclipse–>New–>WorkItem.
Sorry, no idea. It worked for me in the Eclipse client for testing. It was sometimes flaky when debugging, but it seemed to work as expected in my tests.
I have 2 RTC Eclipse, this workitem working in one eclipse only. I am looking on in another RTC Eclipse.
Thanks for your reply Ralph.
In order to use this example with RTC 6.0.6 I had to update the version of Java specified in the manifest. I am now using to Java 1.8 and this allows the plugin to load.
Thanks.
Hello Ralph,
I am developing the java based attribute customization for adding condition, similar to the example in this article, i have extended only the “com.ibm.team.workitem.common.attributeValueProviders” extension and created single condition.
its working fine for me,
But once i deploy this in the server and configure this using RTC Client for “Read – only Attributes for a condition” my other conditions which are DOJO script based conditions stops working.
as soon as i remove the configuration of my java plug in, then my DOJO script conditions starts working.
Is this expected behavior? or any solutions exists for this?
Can you please let me know if i am missing something here…
RTC Version: 6.0.6
Regards,
Abhilash MM
Hi,
the customizations should be totally independent. So all customizations should work. I do not know how the effect you see could be caused. I would consider looking into the log files.
Hello Ralph,
Sorry for late reply…
I have tried adding component extension also in my plug in but still i am not able to use both java provided plug in and script based attribute validations together.
You can see the logs in below link
https://wp.me/p8wzYg-j
i was not sure how to share logs, so i created a blog for that 🙂
Regards,
Abhilash
Hi Abhilash,
there is basically no way for me to help here. I can not debug from here, I can not click the stack trace to get to the classes. I fear I can not help you.