How can the Rational Team Concert Extensions workshop be changed to be easier to use with newer versions of Rational Team Concert?
This is a question that I was contemplating about since I picked up the maintenance of the workshop. The issue with the workshop is the requirement to import database content using the repotools.
Why is that step required? The main reason is, that the workshop provides a project with SCM data that you use to perform the various labs. It also provides the Launch files needed for launching the Jetty server and the Eclipse clients. This avoids a lot of work in typing source code and importing projects.
However, it causes a lot of issues.
- This used to work with various versions of RTC in the past but since 4.0 it seems to be tied to the version that was used to export the databases. So in order to run the workshop with a newer versions, it is neccessary to set it up with the RTC version it was created with and then upgrade the repository to the desired version.
- By importing the repository, the public URI is set.
- When setting the repository up, it is necessary to decide which applications to set up and register. If using a different install method and not installing all applications the JTS will show broken application registrations.
- It is necessary to run a custom setup, due to the usage of the user ID ADMIN
There are some other issues with this approach that add unnecessary complexity to a workshop that is already challenging enough (for example the usage of user ADMIN and how to provide that user with a license). These can hopefully be addressed somehow.
Solution Approach
The only feasible approach that I could come up with was to provide some automation to perform the steps I have to do to set up the repository to export it for a new workshop version. The automation would run against a RTC Server that has a finalized set up of any kind (Express or Custom) with or without existing projects, create and provide the required data.
The minimal set of steps required would be to:
- Deploy the required Template for a Project Area, if it is not already deployed.
- Create the required Project Area for the Extension Workshop.
- Set the required User Membership and Roles for the Project Area.
- Set up the required Stream, Components and the Repository workspace
- Share the SCM Data to the Components, deliver it to the Stream and create the required Baselines. This needs to be done multiple times for the workshop code adding new files and modifying files that already exist.
- Set the repository workspace components to the baselines needed to start the workshop.
Recently I found some time to explore how this can be achieved. I made considerable process and I think there is a solution to this challenge that I might be able to publish. While I will try to find time to finalize the work and get approval to publish the results, I wanted to publish some of the lessons learned from trying to create the solution.
The solution is described in:
- This post
- Managing Workspaces, Streams and Components using the Plain Java Client Libraries
- Delivering Change Sets and Baselines to a Stream Using the Plain Java Client Libraries
- Extracting an Archive Into Jazz SCM Using the Plain Java Client Libraries
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.
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.
Preparing the Project
This post will show how the required project can be created. Some of the code used here is from Snippet 3 of the plain Java Client Libraries and from code already published in this blog. The code that follows is wrapped into the code I usually use for my Plain Java Client Library examples, derived from the Programmatic Work Item Creation Wiki entry and the Plain Java Client Libraries Snippets.
The main() method starts the Team Platform, creates the new class object and passes the arguments on to perform the work. I have discussed what this code does so often in other posts, please refer to them if you have questions.
public static void main(String[] args) throws Exception { boolean result; System.out.println("Starting Team Platform"); if (!TeamPlatform.isStarted()) TeamPlatform.startup(); try { System.out.println("Team Platform started"); ServerSetup setupExtDevServer = new ServerSetup(); result = setupExtDevServer.run(args); } catch (TeamRepositoryException x) { x.printStackTrace(); result = false; } finally { TeamPlatform.shutdown(); } if (!result) System.exit(1); }
In the run() method the work to do is coordinated and performed. The method checks if the required parameters are available. Then it logs into the repository with the given user name and password. This code is presented at the end of this post, as it is just refactored out and is simply the code I am always using in this blog. The user has to have the JazzAdmin repository role.
In the next step the automation deploys the required process template. It then tries to find if the project area exists and creates a new one if not. It adds the required user with role to the project area. The following steps will be explained in later posts.
private boolean run(String[] args) throws Exception { if (args.length != 3) { System.out.println("Usage: ServerSetup repositoryURI userId password"); return false; } String repositoryURI = args[0]; String userId = args[1]; String password = args[2]; IProgressMonitor monitor = new NullProgressMonitor(); ITeamRepository teamRepository = logIntoTeamRepository(repositoryURI, userId, password, monitor); IProcessDefinition scrumProcess = findOrDeployTemplate(teamRepository, "scrum2.process.ibm.com", monitor); IProjectArea area = findOrCreateProjectArea(teamRepository, "RTC Extension Workshop", scrumProcess, monitor); addUsersAndRoles(teamRepository, area, monitor); . . . . .
In the deployTempate() method the automation tries to find the required process template and tries to deploy it, if it was not already deployed.
private IProcessDefinition findOrDeployTemplate(ITeamRepository teamRepository, String processID, IProgressMonitor monitor) throws TeamRepositoryException { System.out.println("Trying to find or deploy template: " + processID); IProcessItemService service = (IProcessItemService) teamRepository .getClientLibrary(IProcessItemService.class); IProcessDefinition[] definitions = null; // Find the process definition IProcessDefinition processDefinition = processItemService .findProcessDefinition(processID, null, monitor); if (processDefinition == null) { // Create the definition if it does not exist. definitions = processItemService .deployPredefinedProcessDefinitions( new String[] { processID }, monitor); System.out.println("Template deployed..."); if (definitions.length != 0) { processDefinition = definitions[0]; } else { throw new TeamRepositoryException("Process template " + processID + " does not exist."); } } System.out.println("Template found..."); return processDefinition; }
The main task is now to find the project area if it exists and to create a new project area in case it is not available.
private IProjectArea findOrCreateProjectArea( ITeamRepository teamRepository, String projectName, IProcessDefinition processDefinition, IProgressMonitor monitor) throws TeamRepositoryException { // Create Project Area based on Scrum System.out.println("Trying to find or create Project Area: " + projectName); IProcessItemService service = (IProcessItemService) teamRepository .getClientLibrary(IProcessItemService.class); IProjectArea area = null; List areas = service.findAllProjectAreas( IProcessClientService.ALL_PROPERTIES, monitor); for (Object anArea : areas) { if (anArea instanceof IProjectArea) { IProjectArea foundArea = (IProjectArea) anArea; if (foundArea.getName().equals(projectName)) { area = foundArea; System.out.println("Project Area found: " + projectName); return area; } } } // Could not find the the project area, create one if (area == null) { System.out.println("Trying to create Project Area: " + projectName); area = service.createProjectArea(); area.setName(projectName); area.setProcessDefinition(processDefinition); IDescription description = area.getDescription(); description.setSummary("Project to be used running the RTC Extension Workshop"); area = (IProjectArea) service.save(area, monitor); area = (IProjectArea) service.getMutableCopy(area); service.initialize(area, monitor); System.out.println("Created and initialized Project Area: " + projectName); } return area; }
Now that the project area is available make sure to add the required user with role ID “ScrumMaster”. The method addUsersAndRoles() does this.It first tries to find the role. Once found it adds the currently logged in user, the user that runs this automation, to the administrators section of the project and to the members section with the role obtained.
private IProjectArea addUsersAndRoles(ITeamRepository teamRepository, IProjectArea area, IProgressMonitor monitor) throws TeamRepositoryException { IProcessItemService service = (IProcessItemService) teamRepository .getClientLibrary(IProcessItemService.class); area = (IProjectArea) service.getMutableCopy(area); System.out.println("Trying to add members with roles: " + "ScrumMaster" + " to Project Area" + area.getName()); // IProjectArea wArea = (IProjectArea)service.getMutableCopy(area); IContributor member = teamRepository.loggedInContributor(); IRole role = getRole(area, "ScrumMaster", monitor); area.addAdministrator(member); area.addMember(member); area.addRoleAssignments(member, new IRole[] { role }); IProcessItem[] items = service.save(new IProcessItem[] { area }, monitor); System.out.println("Users with Roles added to " + area.getName()); return area; }
To get the role the getRole() method tries to discover the roles in the process that have a matching ID and returns it, if it was found. Please note that IRole objects have no access to the role name. they have just the ID. If you need the role name you need to get the IRole2 interface from the IRole object. The code that does this is commented out below.
private IRole getRole(IProcessArea area, String roleID, IProgressMonitor monitor) throws TeamRepositoryException { ITeamRepository repo = (ITeamRepository) area.getOrigin(); IProcessItemService service = (IProcessItemService) repo .getClientLibrary(IProcessItemService.class); IClientProcess clientProcess = service.getClientProcess(area, monitor); IRole[] availableRoles = clientProcess.getRoles(area, monitor); for (int i = 0; i < availableRoles.length; i++) { IRole role = availableRoles[i]; // IRole2 role2 = (IRole2)role; // role2.getRoleName(); if (role.getId().equalsIgnoreCase(roleID)) return role; } throw new IllegalArgumentException("Couldn't find roles"); }
The code left out is for logging into the repository, for completeness it is presented below.
private ITeamRepository logIntoTeamRepository(String repositoryURI, String userId, String password, IProgressMonitor monitor) throws TeamRepositoryException { System.out.println("Trying to log into repository: " + repositoryURI); ITeamRepository teamRepository = TeamPlatform .getTeamRepositoryService().getTeamRepository(repositoryURI); teamRepository.registerLoginHandler(new LoginHandler(userId, password)); teamRepository.login(monitor); System.out.println("Login succeeded."); return teamRepository; } /** * Login Handler implementation * */ private static class LoginHandler implements ILoginHandler, ILoginInfo { private String fUserId; private String fPassword; private LoginHandler(String userId, String password) { fUserId = userId; fPassword = password; } public String getUserId() { return fUserId; } public String getPassword() { return fPassword; } public ILoginInfo challenge(ITeamRepository repository) { return this; } }
Summary
The code in this post basically shows how to prepare a project for later usage. It does the steps requires such as deploying a process template in case it is not yet available. It finds or creates the project area and it makes sure to add the user required as administrator and member with the required role.
Now that the project is prepared, the next steps will be all the required preparation in the Projects SCM to be able to upload the code. This is going to be presented in a later post.
As always, I hope that sharing this code helps users out there, with a need to use the API’s to do their work more efficient.
Hi Ralph,
I`m Surender , working as a software engineer.
I`m Developing a RTC plugin which needs to set the current iteration for the work item.
I know we can do this when we are saving the work item for the first time but my requiremnt is to populate that field with current iteration at the time the user opens the new work item creation dialog. please let me know if this is possible.
sorry if this was not the right thread to post this question.
Thanks
Surender
You can set the iteration and there are several posts on this blog that you can look into for more information. you can use the search field on the top right. https://rsjazz.wordpress.com/2012/10/05/handling-iterations-automation-for-the-planned-for-attribute/ is one of them.
You would have to identify the iteration as current, which I have no code for right now. And you will have to use the ‘Planned For’ attribute. You might have to set the filed against also.
It is not clear to me what you try to achieve.
Thanks for quick reply , My question is
When I click on new work item and select a Story and click on ok then it takes us to a new window where we provide appropriate values and then we save the work item. I have an attribute “Iteration planned” for which I want to set the current iteration before saving or creating the work item.
Thanks
Surender
You still explain what you think the implementation should look like, not what you want to achieve and why.
I am not sure how you could extend that menu actions. Also, on what basis would you choose the current iteration? The work item first needs a category (filed against) and the current iteration would have to be set for the iteration in the timeline the team is selected by the category. You could use a calculated value provider, may be, if you can find rules for the calculation of the iteration. But calculated value attributes should be read only. Search for ‘provider’ to find the article about provider.
I think I would use a side follow up action to set the iteration, just because that would work with all UI’s and only needs to be installed in the server.
You can not set any values before creating the work item.
Is this possible Ralph,
if so could you please guide the right way to do it.
Basically Im confused with API I mean which code needs to be reffered and in the link you mentined above it seems like astandalone application.
Thanks
Surender
please ignore the abovve comment I`v not looked your response
Thanks
Surender
If you want a broader audience that might have done something similar, ask here: https://jazz.net/forum and tag the question with extending.
Hi Ralph,
I would need to create ~2000 project areas but in RQM. Do you know if this API also works for RQM?
Hi Krzysztof,
in the past part of the RTC Java API worked with other products and it still works with JTS for the pieces that JTS has e.g. user management.
I am not sure it will work with RQM however. On the bright side you could try it.
Another option is this: https://jazz.net/wiki/bin/view/Main/LPAAPIExampleClient#Sample_code_to_create_a_Lifecycl
You could set up a template and use the REST API to deploy it multiple times. See the Interesting Links page for other interesting links.
Hi,
When we tried to deploy an existing template with existing project area, update of process template was not happened.
Does deployTempate() does not deploy to the Project Area which is already created with other process template.
This is because once a project area is created, the process is in the project area and can only be changed there. The template is only deployed to it once. See https://jazz.net/wiki/bin/view/Deployment/RTCProcessFundamentals to understand the most basic fundamentals of RTC.
Hi,
How to create project using the process configuration from another project area in plain java code.
If you talk about process sharing, see https://rsjazz.wordpress.com/2014/11/28/the-process-sharing-api/
If not, you have to create a process template from tat other project area first. I don’t have examples for that, but I am relatively sure there are some in Jazz.net answers.
Hello everybody. First of all thanks Ralph, you are an icon for us developers on RTC. Since I am not succeeding with the Rest api I am trying to switch to the Java ones to be later become services. I followed your guide to the letter and created the PA correctly, but I have two questions to ask:
– How is the PA initialized?
– How can I tell it to inherit the configuration process from another?
In my opinion you could expand this guide by inserting these two info, which however have to do with the public administration. Thanks in the meantime.
I also add one thing, I found this link: https://jazz.net/forum/questions/111660/programmatically-finding-the-process-template-used-in-a-project
But from what I understand you “overwrite” the processConfigurationSource and this is not good for me, as the processConfigurationSource of the “children” is empty, as it is inherited, in this way you have it identical but you do not have the “synchronization” between parent and child , at least from what I understand …
The project areas that use the shared process must be instantiated using the “Unconfigured Process”, of course.
As I answered in the forum, you have to send the JSESSIONID in the POST call. I have successfully created 5 project areas with the REST API this morning.
Go into the plain java client libraries and get the sample snippets. The snippets create a new project and team area. Perform Lab 1 of the latest version of the RTC Extensions Workshop to understand how to setup for Plain Java development (see getting started). Once you have set that up correctly, you can search the SDK and the unit tests etc. for code you are interested in.
I do not know if I still have the examples with code how to enable process sharing and how to share a process. I do not know if I have the hours to sieve through the old code to find the code.
I forgot I had blogged about that.
There is a search window on my blog. Top right. Type ‘Process Sharing’ and hit enter. Open the blog post and have a look at the Process Sharing API.
The project initialization is used in the aforementioned snippet.
Thank you very much, but I will tocken it to him or at least from Postman that’s how it seems, if you tell me how to turn your screenshots I’ll show them to you.
As for the apiJava instead, I managed to create it but I can’t initialize it because it “automatically” inherits the preconditions (or I imagine it inherits from the process) and therefore it is not “initialized” but I think I will be able to overcome the problem as soon as I can tell him to inherit the configuration process, because I tried manually and I succeeded so I guess the same way with client api succeeds.
For the rests instead I would also ask you for some screens, I have tried them all on postman but I always get 403 forbidden, but I didn’t want to divulge myself about the Rest here since maybe it can be OT.
Thank you very much, but I will tocken it to him or at least from Postman that’s how it seems, if you tell me how to turn your screenshots I’ll show them to you.
As for the apiJava instead, I managed to create it but I can’t initialize it because it “automatically” inherits the preconditions (or I imagine it inherits from the process) and therefore it is not “initialized” but I think I will be able to overcome the problem as soon as I can tell him to inherit the configuration process, because I tried manually and I succeeded so I guess the same way with client api succeeds.
For the rests instead I would also ask you for some screens, I have tried them all on postman but I always get 403 forbidden, but I didn’t want to divulge myself about the Rest here since maybe it can be OT.
And yes, in the end I found it, I just have to apply it to the above and try it, I just wanted to understand why I can’t now as for the rest services.
The last two answers make no sense to me. If you want an answer on the Jazz.net conversation, ask there.
As for additional screen shot, this comment section is absolutely not made for screenshots. I try to help readers with the first steps in my blog. How they expand on that is up to them. This is not a ‘write that code for me’ blog. If you have questions or comments beyond the content of the individual blog post, please try your luck on https://jazz.net/forum .
I’m sorry they don’t make sense to you, but that’s the situation I find myself in.
Postman, I make the call with the cookie and it returns 403 Forbidden.
For the java api, when I inherit a template that has “customizations” these prevent me from doing the initialization both on the api side and on the web side.
Anyway I will reply to the post I opened by putting the screens if I can. Thank you.
Welcome in the club.
As already explained in the Jazz.net question the 403 is due to the fact that any POST against a Jazz Application requires a header
X-Jazz-CSRF-Prevent
to be sent, where the value of the header contains the value of the cookie JSESSIONID from the last call.
If you do not have the reputation upload images somewhere lese and provide the link. Otherwise use Chrome with images.
Do not expect the forum can solve all your problems. You will have to find out how to deal with stuff.
I imagine that even on the forum they cannot help me to solve them all, God forbid, but if I bump into errors in which someone has already passed, maybe they can answer me.
However I lost this parameter yesterday, now I can but I can confirm that if the process template has preconditions, these do not initialize the PA and is valid for the web, for the Java api and for the Rest Api. I have also seen for the screens then I will find a way if needed, thanks.