Hello Jazz — How to write a simple Jazz component
This tutorial walks you through the process of creating a very simple Jazz™ component with both client and server contributions. As a prerequisite for this tutorial, you should be familiar with Eclipse plug-in development.
Overview of the Process
We will develop a Jazz component with a single service method that returns the string “Hello, Jazz!” from the server to the client. This component will consist of three plug-ins (common, client library and service), plus a JUnit test plug-in.
These are the basic steps we’ll take to create the component:
- Create the common plug-in, defining the Hello Jazz service interface.
- Create the client library plug-in, exposing our service to clients.
- Create the test plug-in, running against the client library. The test we develop will fail until we implement the service.
- Create the service plug-in, implementing our Hello Jazz service. Our test now passes.
The completed plug-ins developed during this tutorial can be found in the file com.example.hellojazz-plugins-source.zip
Setup Steps
Before you begin the tutorial you will need to setup an environment for Jazz component development. Refer to the setup topic on the jazz.net wiki for instructions on how to do this.
Notes for use with Rational Team Concert 2.0
The setup steps on the wiki referenced above have been updated with notes for RTC 2.0. One difference relevant to this topic is that you will need to create separate workspaces for the client and server aspects of the code.
The server workspace should contain these projects:com.example.hellojazz.common
com.example.hellojazz.service
com.example.hellojazz.common
com.example.hellojazz.client
com.example.hellojazz.client.tests
com.example.hellojazz.rcp.ui
Note that the
com.example.hellojazz.common
Additionally, the client launches for the Junit test and the Eclipse IDE will not be able to use the
-Dcom.ibm.team.core.tests.repo=local
REPOSITORY_URI
https://localhost:9443/jazz
Define the Service Interface
Jazz components typically have a
common
Create the Common Plug-in
Create Plug-in Project
com.example.hellojazz.common
Specify the name of the project (
com.example.hellojazz.common
Disable the creation of the activator, and click Finish to create the plug-in.
Setup the Plug-in Dependencies
Our Hello Jazz common plug-in will depend on the common plug-in of the Jazz Repository component. Open the manifest of our new plug-in, select the Dependencies tab, and add
com.ibm.team.repository.common
Declare the Hello Jazz Component
We need to declare our component by extending an extension point defined by
com.ibm.team.repository.common
com.ibm.team.repository.common.components
Note: As the image shows, you may see two instances of the extension-point. You can select either one.
Now fill in our component’s details:
Create the Service Interface
Now let’s create the
IHelloJazzService
And add a
sayHello
package com.example.hellojazz.common.service;
import com.ibm.team.repository.common.TeamRepositoryException;
public interface IHelloJazzService {
String sayHello() throws TeamRepositoryException;
}
Calls to
sayHello
sayHello
TeamRepositoryException
Declare the Service Interface
Now that we have the interface defined, we can tell Jazz about it by adding more information to our extension of the
com.ibm.team.repository.common.components
Set the details of the service element as shown below:
We need to export the service package in order for the client and service plug-ins to see it. Switch to the Runtime tab and add the
com.example.hellojazz.common.service
Client Library
Create the Client Library Plug-in
Each component providing client-side services does so with a client library plug-in. Create a plug-in named
com.example.hellojazz.client
Setup the Client Plug-in Dependencies
Our Hello Jazz client library plug-in will depend on the common plug-in we defined above, and also on the common and client plug-ins of the Jazz Repository component.
In the manifest editor, switch to the Dependencies tab and add these required plug-ins:
-
com.ibm.team.repository.common
-
com.ibm.team.repository.client
-
com.example.hellojazz.common
Create the Client Interface
Now let’s create the
IHelloJazzClientLibrary
package com.example.hellojazz.client;
import com.ibm.team.repository.common.TeamRepositoryException;
public interface IHelloJazzClientLibrary {
String sayHello() throws TeamRepositoryException;
}
For our simple service, it happens that this client library interface’s sole method is identical to that of the service. More sophisticated client libraries may not have such a direct mapping between client library methods and service methods. For example, there can be methods dealing with client-side state (i.e. which don’t need to invoke service methods), and methods which invoke multiple service methods (though this should be kept to a minimum as it implies multiple round-trips to the server).
Export and Declare the Client Library Interface
We need to export the client package in order for other plug-ins to see it:
Now let’s tell Jazz about this interface by extending the
com.ibm.team.repository.client.clientLibraryFactory
In the manifest editor, switch to the Extensions tab, click Add, and double click
com.ibm.team.repository.client.clientLibraryFactory
factory
com.example.hellojazz.client.IHelloJazzClientLibrary
Next click on factoryClass*:
HelloJazzClientLibraryFactory
Note that we set the package to
com.example.hellojazz.client.internal
ClientLibraryFactory
createClientLibrary
@Override
public Object createClientLibrary(IClientLibraryContext context) {
return new HelloJazzClientLibrary(context);
}
Create the Client Library Implementation
Let’s implement the client library class. First we need the constructor:
package com.example.hellojazz.client.internal;
import com.example.hellojazz.client.IHelloJazzClientLibrary;
import com.example.hellojazz.common.service.IHelloJazzService;
import com.ibm.team.repository.client.util.IClientLibraryContext;
import com.ibm.team.repository.common.TeamRepositoryException;
public class HelloJazzClientLibrary implements IHelloJazzClientLibrary {
/**
* The client library context, which identifies the repository,
* and provides access to services.
*/
private final IClientLibraryContext context;
/**
* Creates the {@link IHelloJazzClientLibrary} implementation.
*
* @param context
* The client library context. Must not be null.
*/
HelloJazzClientLibrary(IClientLibraryContext context) {
if (context == null) {
throw new IllegalArgumentException(
"context must not be null");
}
this.context = context;
}
Next we need a private method that will return an implementation of IHelloJazzService. On the client the implementation is a proxy generated by calling
IClientLibraryContext.getServiceInterface(Class cls)
/**
* Returns the {@link IHelloJazzService} implementation.
* @return Returns an {@link IHelloJazzService} implementation.
* Never null.
* @exception TeamRepositoryException
* Thrown if the {@link IHelloJazzService} cannot be
* retrieved.
*/
private IHelloJazzService getService()
throws TeamRepositoryException {
IHelloJazzService service = (IHelloJazzService)
context.getServiceInterface(IHelloJazzService.class);
if (service == null) {
throw new TeamRepositoryException(
"Unable to get IHelloJazzService");
}
return service;
}
We’re now ready to invoke the service:
/**
* Calls the IHelloJazzService.sayHello method on the server, and
* returns its result.
*
* @return The string returned from the server.
* @exception TeamRepositoryException
* Thrown if something goes wrong.
*/
public String sayHello() throws TeamRepositoryException {
String result = getService().sayHello();
return result;
}
} // End of the class
Create the Test Plug-in
Let’s create a JUnit plug-in test that exercises our service. It will initially fail because we’ve not yet created the server-side implementation. Start by creating a new plug-in named
com.example.hellojazz.client.tests
Setup the Plug-in Dependencies
Add the plug-in dependencies we’ll need in the Dependencies tab of the manifest editor:
- org.junit
- org.eclipse.core.runtime
- com.ibm.team.repository.common
- com.ibm.team.repository.client
- com.example.hellojazz.client
Create a test class,
TestHelloJazz
TestCase
package com.example.hellojazz.client.tests;
import junit.framework.TestCase;
import com.example.hellojazz.client.IHelloJazzClientLibrary;
import com.ibm.team.repository.client.ITeamRepository;
import com.ibm.team.repository.client.TeamPlatform;
import com.ibm.team.repository.common.TeamRepositoryException;
public class TestHelloJazz extends TestCase {
private ITeamRepository repo;
protected void setUp() throws Exception {
super.setUp();
if (!TeamPlatform.isStarted())
TeamPlatform.startup();
repo = login();
}
protected void tearDown() throws Exception {
repo.logout(null);
assertFalse(repo.loggedIn());
repo = null;
super.tearDown();
}
public void testSayHello() throws TeamRepositoryException {
IHelloJazzClientLibrary library = (IHelloJazzClientLibrary) repo
.getClientLibrary(IHelloJazzClientLibrary.class);
assertNotNull(library);
String result = library.sayHello();
assertNotNull(result);
return;
}
/**
* The URI scheme <code>"local:"</code> creates a Jazz server on the same
* thread as the client.
*/
private static final String REPOSITORY_URI = "local:";
private ITeamRepository login() throws TeamRepositoryException {
ITeamRepository repository = TeamPlatform.getTeamRepositoryService()
.getUnmanagedRepository(REPOSITORY_URI);
assertFalse(repository.loggedIn());
repository.registerLoginHandler(new ITeamRepository.ILoginHandler() {
public ILoginInfo challenge(ITeamRepository repo) {
return new ILoginInfo() {
public String getUserId() {
return "ADMIN";
}
public String getPassword() {
return "ADMIN";
}
};
}
});
repository.login(null);
assertTrue(repository.loggedIn());
return repository;
}
}
Running the test
To simplify matters, we’ll run in local mode (i.e. client and server will be in the same process). Running this way avoids the need to deploy your common and service plug-ins, and is thus a convenient way to test changes to your common and service plug-ins; if you’re only changing your client plug-in, you’ll want to run your service in a separate Jazz server so that it isn’t necessary to restart the server with each change.
Now we’re ready to run the test we’ve written. Create a JUnit Plug-in Launch, with
TestHelloJazz
[No Application] – Headless Mode
-Dcom.ibm.team.core.tests.repo=local
- -Dcom.ibm.team.repository.db.jdbc.location="${target_home}/../../server/repositoryDB"
The first argument specifies to use local mode and the second argument identifies the location of the Jazz repository database. This example does not make explicit use of the repository database, but the Jazz Team Server still needs to be able to locate a database. The database path shown above should point to the default one. (Note that the HelloJazz download includes a launch file named
TestHelloJazz.launch
When we run this, we’ll find that
HelloJazzClientLibrary.getService
Service Plug-in
Create the Service Plug-in
Our server-side implementation of the IHelloJazzService will be in plug-in
com.example.hellojazz.service
As this plug-in is used (only) on the server, its dependencies are correspondingly different:
- com.ibm.team.repository.common
- com.ibm.team.repository.service
- com.example.hellojazz.common
Declare the Service Implementation
Let’s now declare the service implementation via the
com.ibm.team.repository.service.serviceProvider
plugin.xml
<extension
point="com.ibm.team.repository.service.serviceProvider">
<serviceProvider
componentId="com.example.hellojazz"
implementationClass=
"com.example.hellojazz.service.internal.HelloJazzService">
<provides>
<providedService interface=
"com.example.hellojazz.common.service.IHelloJazzService"/>
</provides>
</serviceProvider>
</extension>
We used here the same componentId value (
com.example.hellojazz
Implement the Service
Service implementations must extend
AbstractService
package com.example.hellojazz.service.internal;
import com.example.hellojazz.common.service.IHelloJazzService;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.service.AbstractService;
public class HelloJazzService
extends AbstractService
implements IHelloJazzService {
public String sayHello() throws TeamRepositoryException {
return "Hello Jazz!";
}
}
Running the Test, Again
When we run the test now, we find that it passes:
A good learning exercise at this point is to set breakpoints in the test, and in the client and server implementations, and run the test again under the debugger. This allows one to examine the call stacks that are involved.
You’re ready now to embark on the exciting task of developing your own Jazz component. Have fun!
Bonus Client UI Plug-in
The source code download for this example now contains an additional plug-in, com.example.hellojazz.rcp.ui. This plug-in demonstrates how to create a simple Eclipse UI for the HelloJazz service.A launch configuration called HelloJazzClient is been provided with the plug-in. Open this configuration (Run > Open Run Dialog…) and verify that the VM argument -Dcom.ibm.team.repository.db.jdbc.location correctly identifies your test repository database. Now run the configuration and wait for the Jazz client to start. In the new Jazz client, find or open the Team Artifacts view and create a new Jazz Repository Connection with the values shown below (use ADMIN for the password in the dialog).

Now find your new repository connection in the Team Artifacts view, right-click on it and select Call IHelloJazzService from the context menu.

You should see a message dialog indicating the service method was called. (Note that the repository URI may differ from what you typed in, as shown below.)

To understand what happened and why it worked, first examine the plugin.xml in the com.example.hellojazz.rcp.ui plug-in. It contains an object contribution popup menu action for the object class ITeamRepository.
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
id="com.example.hellojazz.rcp.ui.helloJazzPopup"
objectClass="com.ibm.team.repository.client.ITeamRepository">
<action
class="com.example.hellojazz.rcp.ui.actions.HelloJazzAction"
id="com.example.hellojazz.rcp.ui.helloJazzAction"
label="Call IHelloJazzService">
</action>
</objectContribution>
</extension>
The object you see in the Team Artifacts view representing your repository connection is an ITeamRepository, so the action defined here will be added to its context-menu. Now note the action class HelloJazzAction and examine that class. You will see code to obtain the IHelloJazzClientLibrary and call the sayHello() method, as was done in the JUnit test case above. However there is additional code here to obtain the ITeamRepository from the UI selection and to make the service method call in a background thread.
Discussion