CodeBeamer Web Services API (Remote API) & Listener API

This document describes how to use CodeBeamer’s API to develop custom applications. This document provides information for software developers.

Introduction

The CodeBeamer web services API provides a simple, secure and effective programmatic interface to manipulate CodeBeamer data from your remote applications, i.e. applications that run in a separate JVM, mostly on a separate computer.

You will find API examples on your installation kit in the ZIP file:

../installdir/tomcat/webapps/cb/codebeamer-api-6.X.X.zip

Using the Listener API, you can write so-called listeners that can receive notifications from events in a CodeBeamer server. The CodeBeamer listener architecture follows the observer design pattern conventions that are familiar to most Java developers.

The proper use of these two extension points allow you to customize, extend and integrate with the CodeBeamer server.

Extension Points

The CodeBeamer platform is highly extensible both on the client and server side. The following figure shows the overall architecture and extensibility of the platform.

Figure: CodeBeamer conceptual extension points

All extensions plug into the business logic. The extensibility mechanism also provides a means of accessing information from both the repository and the web interface with the mediation of the business logic.

CodeBeamer Web Services API (Remote API)

Overview

The Web services API is a programmatic interface which provides the ability to manipulate CodeBeamer objects such as projects, users, trackers and documents. Developers can write applications in programming languages such as Java and C# to access and manipulate CodeBeamer data objects. The Web Service API calls are remote calls and produce actions on the CodeBeamer server.

For example, the developer can create applications that:

  • Create a document
  • Create/Update/Delete a tracker issue
The Quick Start section provides more ideas on usage scenarios for the Web Services API.

Technology Background

The CodeBeamer Web Services API is based on the Hessian binary web service protocol, developed by Caucho. The Web Service API provides a CodeBeamer-specific layer on top of it that makes this protocol transparent to the API user.

Hessian has been chosen as the underlying layer for the Web Services API due to the numerous advantages it provides to the Web Services API user, including:

  • extremely easy to use API since Hessian objects are very similar to plain Java objects;
  • high performance since it uses a binary protocol (instead of verbose XML);
  • it uses a multi-language protocol and the clients can be in virtually any language; while CodeBeamer currently ships with only a Java API, on demand the CodeBeamer Web Services API can be made available for C++, C#, Python, PHP and Ruby.

The Web Services API require a Java Development Kit (JDK) version 1.6 or higher which is the same requirement as for Hessian.

Supported Operations

The Web Services API provides classes and interfaces for the most important codeBeamer services.

The following table summarizes the packages, classes and interfaces of the API and presents a description of the types of methods for each entity:

Table Remote API components

Class/InterfaceDescription Types of methods
Package com.intland.codebeamer.remoting Provides the central point of working with the codeBeamer server.
RemoteApi interface The facade interface to the worker class used for operations with the codeBeamer server.Authentication, server and session information retrieval and, most importantly, Create / Retrieve / Update / Delete operations on all entities, using Data Transfer Objects (see the com.intland.codebeamer.persistence.dto package below).
DescriptionFormat interfaceDefines formatting options available for codeBeamer text data.None, as this is a string-constants-only interface.
Package com.intland.codebeamer.remoting.bean Information wrapper classes.
ServerInfo classWraps information about the remote codeBeamer server.Getter methods for retrieving information about the codeBeamer server version, the Java version the server is running on, the server side operating system and others.
Package com.intland.codebeamer.persistence.dto Data transfer objects for remote operations to be executed remotely on the codeBeamer server.
ArtifactDto, ArtifactAdditionalInfoDto, ArtifactAssociationDto, ArtifactHistoryEntryDto, ArtifactNotificationConfigDto and ArtifactStatusDto classesThe transfer objects contain artifact related information. An artifact is typically a directory, a document or a wiki page.Getter and setter methods for id, name, description, type, status, relationships, access rights for the current user, revision, scheduling and others. Statistical information is also available.
AssociationDto and AssociationTypeDto classesThe transfer objects contain artifact association related information.Getter and setter methods for id, description, source and destination entity IDs and types, submitter and URL.
BuildDto and BuildLogDto classesInformation for scheduled builds and their executions.Getter and setter methods are available for name, id, status, custom command line properties, status, build interval and various aspects of the build log.
ForumDto, ForumNotificationDto, ForumPostDto, and ForumTypeDto classesForum and forum posts related information.Getter and setter methods are available for name, id, description, readability, visibility, type, owner project, user notifications, full forum post information, thread level statistics, user level statistics and others.
LoginStatsDto classLogin related information.In the current version, only the maximal number of concurrent accesses is available, for both reading and writing.
ProjectDto classWraps all codeBeamer project information.Getter and setter methods for project name, id, description, home page URL, status, user name, password, category, creation information and others.
ScmRepositoryDto, ScmChangeSetDto, ScmChangeFileDto, and other Scm*Dto classesVersion Control repository and change set related information.Getter and setter methods for number of total, commented and empty lines, file type, directory, file name, modification date, date of last parsing and others.
SourceDirectoryDto, SourceFileDto, SourceFileSymbolDto and other Source*Dto classesSource code information.Getter and setter methods are available for commit counts, revision info, repository, state, tag, file name, directory name, various statistics, tracker item association and others.
TrackerChoiceOptionDto classA property value set entry.Methods are available for reading and writing the entry's value, accessing the associated tracker, entry visibility and others.
TrackerDto classDefines a tracker category and wraps all the related information.This class provides getter and setter methods for tracker name, id, description, type, visibility, container project, visibility, access rights and others.
TrackerItemDto, TrackerItemAttachmentDto, TrackerItemCommentDto, TrackerItemHistoryDto and other TrackerItem*Dto classes.Wrappers for tracker items and associated data.Getter and setter methods are provided for tracker item id, summary, status, categories, visibility, attachment handling, comments, history and others.
TrackerLayoutDto and TrackerLayoutLabelDto classesVisual rendering of choice options.Methods for getting and setting the visual attributes of choice options.
TrackerNotificationDto classUser notifications for tracker items.Getters and setters for working with the associated tracker item, the user and the notification flag.
TrackerTypeDto classData transfer object for tracker types (change requests, bugs, tasks, etc.)Getter and setter methods for the ID and name of tracker types.
UserDto and UserSessionDto classesData transfer object for registered users and their remote sessions.Getter and setter methods available for name, title, password, address, phone, logged in status, login and logout dates, session id, download limit, host name, email client, operating system, team size, skills and others.
WikiPageDto and WikiPageCommentDto classesWiki pages and their comments. Please note that wiki pages are artifacts, so everything related to artifacts applies to wiki pages, too.Getters and setters for the page names, description and others.
WorkflowTransitionDto classVarious workflow transition related information.Getters and setters for the action class, the list of auto asignees, source and target statuses, granted roles, the involved tracker and others.
WorkingSetDto classWorking sets are used to limit the scope when users have a multitude of projects.Getters and setters for the names, types, active state and others.

Several of the above presented entities define a range of methods named using the patterns setUndefined*()/getUndefined*() or setUnused*() and getUnused*() . These methods provide access to fields that can be used to store custom properties with a meaning given by the client application. Please see the API docs for detailed information on the classes and interfaces.

Use Case Examples

The availability of the Web Services API makes the CodeBeamer repository open to third party applications. There are several usage scenarios for the API. Import/export and plug-in scenarios are discussed below.

Importers and Exporters

The API makes codeBeamer repository information available. Provided the user has full access rights, information can be both read and written. Tools that can import projects, trackers, tracker items or other simpler data chunks from other collaboration tool repositories can be developed using the Web Services API.

Exporting data of an arbitrary level and complexity from the codeBeamer API to third party data stores is another possible usage of the Web Services API.

The fundamental importance of such an API is that codeBeamer users are not limited in any way to the existing mechanisms of data import and export provided by the codeBeamer application and can implement custom mechanisms that best fit their needs. This increases the openness of the codeBeamer repository.

Custom Reporting

Using the Web Service API, custom reports can be created for particular installations of codeBeamer, which is a big increase in functionality over the reporting capabilities of codeBeamer. In this way proven reporting tools like Crystal Reports, JasperReports or Eclipse BIRT can be used to design reports as required.

IDE Plug-ins

Various Java plug-ins of IDEs can use the Web Services API to access and change data on the CodeBeamer server. There are a considerable number of scenarios for this.

A plug-in can intercept source code commits in an IDE, analyze the provided comment and, if it matches a predefined patter, change the status of a Bug Tracker or a Change Request in a codeBeamer repository.

An IDE project creation wizard might be extended by a plug-in to access a codeBeamer project from a repository for the retrieval of project metadata. Based on this information the plug-in could extend the source code editor with new functionalities. For instance, hovering over codeBeamer Wiki references such as [DOC:1237], [BUG:9374] or [TASK:74821] inside source code comments could provide hyperlinks to the specific codeBeamer project pages.

Integration with External Applications

The Web Services API enables the development of proprietary front-ends for codeBeamer. For instance, a portlet can be created to integrate the retrieved information into an existing portal infrastructure.

Existing bug tracking applications can also be enabled to support codeBeamer as a bug tracking repository. codeBeamer uses the common bug tracking idioms so this kind of integration is certainly possible.

Existing document management tools can integrate with the artifact management capabilities of codeBeamer. Document versioning information is readily available.

Basic Concepts

The Web Services API is built on top of the Hessian binary web service protocol. Because of this it inherits its behavioral characteristics. The conversation between the Web Services API client and the codeBeamer server is of request-response type. This leads to a unidirectional synchronous communication: the client fires a request and blocks until the response from the server is received. Basically the server does not provide any kind of information unless it is asked for. No server side notifications are available from the server and no listener mechanism is available for the Web Services API client.

Method calls that alter the codeBeamer repository's data cannot be wrapped inside a transaction. Each method call performs an auto-commit on exit. This way all the communication is stateless so that no data from the client side affects in any way the server side processing flow.

Authentication and Remote Session

For accessing and altering data from a codeBeamer repository a user needs to authenticate itself in the same exact way as he does it on the web-based user interface: by providing his username and his password. The authentication on a codeBeamer server is password based. A successful authentication triggers the creation of a remote session. Thus the session is bound to a user account. The session ends when the user logs out. Alternatively an inactivity timeout set on the server-side can also end a session.

In the Web Services API a remote session is identified by a unique String token. The non-null token object returned by the RemoteApi.login() method uniquely identifies the current session. Once the login has been successful, subsequent API calls require the session token as the first argument. Any API call with an invalid token will be immediately rejected.

The following sequence diagram illustrates the operations inside a session for retrieving all the tracker item names the user has access to:

Figure: Sequence Diagram of Tracker Item Querying


The session token gets invalidated either when disconnecting with the RemoteApi.logout() method or when a connection timeout occurs. The value for the timeout is customizable within each codeBeamer deployment.

Web Services API Security

As the remote session is bound to an existing user account, it has the same permissions as the given account.

For instance, if the given account has no access to a codeBeamer project the RemoteApi.findAllProjects() method call will not include that particular project in the returned array. This works also on field-level so for instance if the account has no read access for a property of an entity then a null value will be returned for it in the data transfer object returned by a getter method. Similarly, if the user has no write access for a property then that property will be ignored when trying to write it from the client side using a setter method.

Atomic Operations

The bidirectional data transfer between the client and the server uses data transfer objects. These are plain JavaBeans (which in fact are plain Java objects - POJOs) for each entity that wrap inside all the available data. This way it is possible to update a single field only for a previously read entity, since all fields must have a value when calling a remote method with a transfer object parameter.

ID Fields

Each entity in a codeBeamer repository is identified by an ID. This ID is also visible to the user. This is useful for instance because references can be made to it from a Wiki type comment.

There is one particular issue regarding the IDs that is important when using the Web Services API. The data type for an ID is a java.lang.Integer object rather than an int primitive type. This requirement exists because the null state of an ID has a special meaning. It signals the lack of an ID. This feature is useful only when creating a new entity and the ID should be provided by the server.

Template Based Artifact Creation

There is a feature in the Remote API to create CodeBeamer artifacts based on the settings of existing ones. Template based creation is currently available for projects, trackers and forums. All template based creations are a one time copy operation of all the involved settings from the source artifact to the target artifact. No content is copied and no links remain between the template artifact and the created artifact. This means that, whatever operations might happen on the contents and settings of the template artifact, these will not affect in any way the artifacts created based on it.

The template based creation of projects takes all the configuration parameters of a project and creates them in the new project. This takes into account the settings for project members, roles, trackers, forums and notifications. Similarly, when creating trackers and forums based on templates, all settings from the source tracker or forum are copied into the newly created artifact.

All the template based creation operations are available through the RemoteAPI interface using the methods: createProjectFromTemplate, createTrackerFromTemplate and createForumFromTemplate.

Error Handling

The Web Services API has certain limitations related to error handling. Exceptions thrown in the CodeBeamer business logic aren't available as checked exceptions. This is due to the fact that the underlying Hessian protocol does not allow the use of checked exceptions for web services. Error situations are signaled by returning the null value from a remote method. When this happens, the client application can retrieve a relevant error message using the RemoteApi.getSessionStatus(String) method. This method returns the stack trace of the exception caught on the server side if the last remote call was unsuccessful or returns null otherwise.

Quick Start

This chapter presents some simple examples on the Web Services API usage. It will help you understand the basic mechanisms in working with a CodeBeamer repository through the Web Services API.

Exporting Tracker Data to CSV Files

This example illustrates an export scenario from the CodeBeamer repository into comma separated values. This is the interaction workflow that the Web Services API performs:
  • Connect to a CodeBeamer server
  • Authentication with a user name and password
  • Retrieve server info
  • Retrieve and export information on users, projects, artifacts, trackers and tracker items. The retrieved information is exported into files (one file for an entity type).
The complete source code is contained in the com.intland.codebeamer .remoting.sample.CodeBeamerCsvExporter class. Please note that the goal of this listing is not to show a full-blown data exporter, but to give a useful sample which serves as good starting point when implementing a real-life exporter fine-tuned for your particular needs. Next the source code is being discussed.

The connection to the repository is performed with the call (codeBeamer 5.5.1 or higher):

RemoteApi api = RemoteApiFactory.connect(serviceUrl);
older codeBeamer versions:
RemoteApi api = RemotingUtils.connect(serviceUrl);                 // Deprecated since 5.5.1

The Remote API URL (the variable serviceUrl in the previous example) is simply the base URL of your codeBeamer instance with /remote-api appended. For instance, if you access CB at http://www.mycompany.com/cb in your browser, then the API is available at http://www.mycompany.com/cb/remote-api.

In case the resulting api instance is null it indicates a connection error. The authentication with the server is performed with the call:

api.login(login, password)
If the login is successful this call returns a non-null value representing the credential token used in all the API calls that work with the data from the CodeBeamer repository. Note that this, like any remote call, might throw a HessianRuntimeException.

To obtain information on the server the following call is used:

api.getServerInfo(token)
The resulting {ServerInfo} object contains information about the server's version, server build date, remote JVM version and the operating system CodeBeamer runs on.

The call

UserDto users[] = api.findAllUsers(token);
for(int i = 0; i < users.length; i++) {
  UserDto user = users[i];
}

retrieves the users from the remote server.

The methods in the UserDto class allow access to information for each user. For instance to see if the user is authenticated, the user.isAuthenticated() method should be called.

To retrieve the projects from the CodeBeamer server the following code is used:

ProjectDto projects[] = api.findAllProjects(token);

for(int i = 0; i < projects.length; i++) {
  ProjectDto project = projects[i];
}

For each project several information is available. Among these the project.getHomePage() method returns the project's Web URL.

The artifacts of all projects are gathered using this snippet:

ProjectDto projects[] = api.findAllProjects(token);

for(int i = 0; i < projects.length; i++) {
  ArtifactDto artifacts[] =

  api.findTopArtifactsByProject(token,
  projects[i].getId());
}

The retrieval of the existing trackers is achieved this way:

TrackerDto trackers[] = api.findAllTrackers(token);
for(int i = 0; i < trackers.length; i++) {
  TrackerDto tracker = trackers[i];
}

Each tracker contains an arbitrary number of tracker items. To access them the following logic is used:

TrackerDto trackers[] = api.findAllTrackers(token);

for(int i = 0; i < trackers.length; i++) {
  TrackerItemDto items[]
             = api.findTrackerItemsByTrackerId(token,
                                               trackers[i].getId());
}

The above code examples illustrate a straightforward use of the Web Services API to retrieve all kinds of information from the CodeBeamer repository. The whole source code for the example is available in the com.intland.codebeamer.remoting.sample.CodeBeamerCsvExporter class.

Importing Tracker Data from CSV Files

Following the same patterns as for exporting data to CSV format a CSV import example application has also been implemented. Its Web Services API interaction is symmetrical to the export example by using the setter counterpart methods. This example is available in the com.intland.codebeamer.remoting.sample.CodeBeamerCsvImporter class.

In this case this is the interaction workflow:

  • Connect to a CodeBeamer server
  • Authentication with a user name and password
  • Import CSV data from CSV files (one file for an entity type) for users, artifacts and tracker items
  • Write data to the CodeBeamer repository.

The usual patterns are used for connection and authentication. The data import from a CSV file is done using a third-party library. The CSV values are stored in a String matrix for each type of entities. The matrixes are than iterated over. In each iteration a new Web Service API data transfer object is created and written to the repository:

api.createUser(token, user)
for creating a new user based on the information wrapped inside the user data transfer object of UserDto type; the ID, registry date and last login properties are set by the server so these are not set by the client;
api.createArtifact(token, artifact)
for the creation of artifacts; the ID, createdAt, lastModifiedAt, lastAccessedAt, lockedByUser and lastModifiedByUser properties are not set since the server will provide values for them; the deleted property is false by default so it does not need to be set;
api.createTracker(token, tracker)
for creating trackers. The ID and createdAt properties are not specified since these will be set by the server.
api.createTrackerItem(token, item)
for creating tracker items; the ID field is not set since it will be provided by the server and the deleted property is false by default so it isn't set. Note that in the current version the Web Services API does not support the creation of projects. This means that for the sample application to work the project and tracker references in the imported CSV data must point to existing projects and, respectively, trackers in the repository.

Document Downloader - Sample Application

This example shows how to download an artifact from a CodeBeamer server.

The following steps are performed:

  • connection to the CodeBeamer server
  • authentication with user name and password
  • searching for a document in the project by recursively traversing the document tree
  • downloading of the document and its storage in a local file
The connection to the CodeBeamer server and the authentication is done similarly to the previous example (CSV import/export sample).

Having identified a project, the following source code is used to search for the document artifact:

ArtifactDto artifact = findArtifactByName(api,
                                          token,
                                          api.findTopArtifactsByProject(
                                                  token, project.getId()),
                                          artifactName);

In case the artifact object isn not null it means that the specified document does indeed exist on the server and can be downloaded this way:

byte data[] = api.downloadArtifact(token, artifact.getId());
Unless the data object is null, it is stored in a local file using the java.io package.In case the data object is null it could mean that the user has no access rights for reading the artifact. To detail the reasons the RemoteApi.getSessionStatus(token) method needs to be called. The full source code for the example is available in the com.intland.codebeamer. remoting.sample.ArtifactDownloader class.

Document Uploader - Sample Application

The implementation for an artifact uploader walks through the following steps:
  • connection to the CodeBeamer server
  • authentication
  • creating a new artifact folder
  • uploading a new artifact consisting of a text file
  • uploading a second revision for the document
The connection and authentication steps are performed similarly to the previous examples. A new folder is created by first instantiating a data transfer object:
ArtifactDto dir = new ArtifactDto();
dir.setProject(project);
dir.setName(dirName);
dir.setDirectory(true);
dir.setDescription("This directory was created through the CodeBeamer API.");
dir.setOwner(user);
The user object is of type UserDto and is obtained with the api.getSessionUser(token) call. After this the data transfer object is sent to the server:
dir = api.createArtifact(token, dir);
Now the document artifact transfer object is created:
ArtifactDto doc = new ArtifactDto();
doc.setProject(project);
doc.setParent(dir);
doc.setName(docName);
doc.setDirectory(false);
doc.setDescription("This document was uploaded through the CodeBeamer API.");
doc.setOwner(user);
The artifact is configured to be uploaded to the server. The following snippet does this:
doc = api.createAndUploadArtifact(
          token,
          doc,
          "This is the binary content of the file.".getBytes(),
          "Initial checkin.",
          DescriptionFormat.PLAIN_TEXT);
The last parameter of the method specifies that the format of the description is plain text. Also notice that the method returns an updated artifact data transfer object. This is because when creating a new entity the server automatically assigns an ID to it and thus the local transfer object becomes outdated.

A second version for the document is uploaded this way:

api.uploadArtifact(token,
                   doc.getId(),
                   ("This is the changed binary content of the file " +
                        "(<strong>second</strong> version).").getBytes(),
                   "Second version.",
                   DescriptionFormat.HTML);
The description for this version is provided in HTML format. This concludes the artifact uploader example application. The full source code for the example is available in the com.intland.codebeamer.remoting.sample.ArtifactUploader class.

Frequently Asked Questions

  • Why are you using wrapper objects instead of primitive types (e.g. java.lang.Integer VS int) ?

Wrapper objects can be NULL, while primitive members cannot and the special semantics of NULL is needed to mark IDs for new objects (to distinguish them for objects to update) or to mark properties that are not accessible by the remote user. Using primitive "0" for these would be misleading. On the other hand, the auto-boxing language feature available since JDK 1.5 will save you some typing.

  • All the methods of the Web Services API throw an unchecked HessianRuntimeException. Why doesn't the Web Services API make use of checked exceptions to report errors?

The only exceptions you can get on the client side come from the protocol itself (e.g. incorrect URL and such), and there is simply no way to recover from those. CodeBeamer exceptions are never propagated from the server side to the client side. You will simply receive NULL as a return value and can ask the server about the session state. This will provide an error message (if the last API call failed) or NULL (if the last API call was OK).

  • Why do I have to handle the return value of the createXxx() methods instead of having the method fill in the passed object with the ID?

    user = api.createUser(token, user);


For the first look, it might look odd. Why do we have to handle the return value? Why cannot the method just modify the object instance passed by injecting the new ID into that?

Well, the reason is that however it looks like a normal Java method call, it's more than that. In the background, your method call will be transparently transformed to a web service invocation by Hessian. Since your request will be handled on the server, in a different(!) JVM, the server doesn't "know" anything about your local "user" object that you passed to the createUser() method. Instead, it will return some return value, that will be used by Hessian to instantiate a new UserDto object, the return value in the above example. The original object and the returned one are, of course, not identical in your local JVM.

Shortly, while working with CodeBeamer's remote API, you have to think in web service invocation semantics, not plain vanilla Java method calls!

Migrating CodeBeamer API applications

See the migration document in Migrating CodeBeamer API Applications.

CodeBeamer Listener API

This functionality can only be used in conjunction with Intland professional services. To become part of the early release community please contact sales@intland.com.

Overview

Listeners give you the power of extending or customizing CodeBeamer by running your plug-in code in a controlled and well-defined way inside the CodeBeamer server. The clear interface between the CodeBeamer core and your custom code will ensure portability for future versions of CodeBeamer. The CodeBeamer event listener architecture is based on the well-known and established “Observer” design pattern. An explanation of the pattern is available here: http://en.wikipedia.org/wiki/Observer_design_pattern. Developers that have worked with Swing, SAX XML parsers, windowing toolkits or any other event-driven system should be already familiar with this pattern.

Figure: CodeBeamer Event Listeners

Listeners in CodeBeamer

You can write so-called listener classes by implementing Java interfaces defined by CodeBeamer and register these listeners either declaratively in an XML configuration file or programmatically in Java code, to the centralized event source called EventMulticaster in CodeBeamer. At startup time, CodeBeamer will automatically instantiate your listener classes, and later notify those objects by calling one of their event handler methods when an appropriate event occurs. CodeBeamer will notify the listener objects by detecting what listener interface or interfaces they implement. For example if you write a TrackerItemListener, it will be notified about events related to tracker items.

The listener interfaces defined by CodeBeamer in the com.intland.codebeamer.event package, so the API documentation of this package will provide you with all the information you need. As a short summary, you can handle the following events:

  • CRUD operations (create, read, update, delete) related to any of the following entities: artifacts, associations, forums, projects, tracker item attachments, tracker item comments, tracker items, trackers and users
  • modification committed event in the SCC listener
  • “artifact opened” event in the artifact listener
  • “transition taken” event in the workflow listener

Please note that the listeners’ code run in the same JVM like the CodeBeamer core, so bugs in the listeners can lead to serious system failures. Before putting to production, your listeners need to be carefully tested. It is recommended to extensively test for any kind of exceptions that the listener code might raise.

As a rule of thumb the code in the interface methods should be wrapped in a try-catch block. All Exception instances should be catched here and a VetoException should be thrown. This ensures that regardless of what unpredictable internal exceptions the listener might raise (e.g. java.lang.NullPointerException), in the worst case the event vetoed. Please consult the Quick Start section for more information on this.

Supported Events

Use Case Examples

This section shows some real-life examples to give some insights how you can customize your CodeBeamer using the listener architecture. You can use listeners for generic notification purposes. For example, you can generate and publish up-to-date RSS/Atom feeds about the tracker items entered. In this case, you simply implement RssGeneratorTrackerItemListener which can use Rome (https://rome.dev.java.net/) to generate feed entries in the identifiableCreated() event handler method.

Another good example is virus checking on the document uploads. You implement your custom VirusCheckerArtifactListener. In its identifiableCreated() handler, you pass the uploaded document to the virus checker module and then use the result returned by this. If the document was found infected, you can throw a VetoException from the event handler which will cause rejecting the upload and the document will not appear in the repository. See more about “vetoing” in the next section.

You can extend CodeBeamer with your custom validation rules. For example, you don’t allow deleting a tracker item unless its status is “Closed”. All you have to do is implement a StatusCheckerTrackerItemListener, and check the trackerItem.status property in its identifiableDeleted() handler. If it’s not closed, you can choose to veto the deletion. Similarly, you can cancel any other entity CRUD operation, thus custom-tailoring CodeBeamer to your internal business rules. The listeners can be used also as enterprise integration platform by implementing reliable, high performance, asynchronous messaging to external systems with JMS (Java Message Service): a CodeBeamer listener can connect to a standard JMS message queue and send JMS messages to this. All the external subscribers will be notified whenever some event happens in CodeBeamer and can react to this immediately.

Basic Concepts

Listener Types

The CodeBeamer Listener API provides a set of listener interfaces for implementing event handlers for the various entities from the repository.

The listeners are located in the com.intland.codebeamer.event package. All listeners derive from the com.intland.codebeamer.event.EventListener interface. This interface provides methods for handling pre-creation, pre-deletion and pre-update vetoable events. The following listener types are available in the CodeBeamer Listener API:

  • ArtifactListener - provides additional notification for artifact opening
  • AssociationListener
  • ForumListener
  • ForumPostListener
  • ProjectListener
  • SccListener - provides an additional method for handling commit events
  • TrackerListener
  • TrackerItemListener - additionally a method is available for post-item removal logic
  • TrackerItemAttachmentListener
  • TrackerItemCommentListener
  • UserListener
  • WorkflowListener
Please consult the API docs for more details on the listeners.

Pre- and Post Events

By timing, there are two types of events in CodeBeamer. “Pre” type events occur before the actual operation, while “post” type events occur after that. It means that the regular sequence when creating a tracker looks like this:

  • all tracker listeners receive the “pre tracker created” event
  • if vetoed, the operation is rejected, end
  • the tracker gets created
  • all tracker listeners receive the “post tracker created” event
  • end

Vetoing

Vetoing means that a listener can actually cancel an operation while the operation is in its “pre” phase. All the listener has to do is throwing a VetoException. When CodeBeamer catches that exception, the operation will be cancelled. In other words, an operation is performed only if none of the registered listener has thrown the VetoException. For obvious reasons, an operation cannot be cancelled in its “post” phase. Please note that vetoing is a powerful mechanism, you have to use with special care, as it can lead to lost information.

Figure: Vetoable listeners behavior for pre-events

The above figure shows that if the operation is vetoed by the custom listener then the initiating business flow will be cancelled.

Quick Start

Implementing a Logger Listener

The following listing shows a trivial implementation of a listener that logs any event happening. You can use this as template code:

public class LoggerListener implements ArtifactListener, ForumListener,
                                       ProjectListener, TrackerListener,
                                       TrackerItemListener, UserListener {
  final static protected Logger log
                          = Logger.getLogger(LoggerListener.class);

  public void identifiableCreated(BaseEvent event) {
    log.debug("identifiableCreated: " + getEventDescriptor(event));
  }

  public void identifiableUpdated(BaseEvent event) {
    log.debug("identifiableUpdated: " + getEventDescriptor(event));
  }

  public void identifiableDeleted(BaseEvent event) {
    log.debug("identifiableDeleted: " + getEventDescriptor(event));
  }

  public void artifactOpened(BaseEvent event) {
    log.debug("artifactOpened: " + getEventDescriptor(event));
  }

  public void trackerItemRemoved(BaseEvent event) {
    log.debug("trackerItemRemoved: " + getEventDescriptor(event));
  }

  protected String getEventDescriptor(BaseEvent event) {
    return (event.isPreEvent() ? "PRE " : "POST ") + event.getUser()
           + " ["+ event.getRemoteAddress() +"] on "+ event.getSource();
  }
}

Note that for logging the Log4j library is used. By doing this logs will be output to the CodeBeamer log file.

Implementing adding a user automatically at project creation

When you want to add a user as "super project administrator" to each newly created project you can use the following template code:

package com.intland.codebeamer.event.impl.sample;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;

import com.intland.codebeamer.event.BaseEvent;
import com.intland.codebeamer.event.impl.DefaultProjectListener;
import com.intland.codebeamer.manager.ProjectManager;
import com.intland.codebeamer.persistence.dto.GroupDto;
import com.intland.codebeamer.persistence.dto.ProjectDto;
import com.intland.codebeamer.persistence.dto.RoleDto;
import com.intland.codebeamer.persistence.dto.UserDto;
import com.intland.codebeamer.persistence.util.PersistenceUtils;
import com.intland.codebeamer.remoting.GroupType;
import com.intland.codebeamer.security.acl.Acl;

/* Example in general.xml:
	<listener class="com.intland.codebeamer.event.impl.sample.AssignAdminAccountToNewProjectListener" id="assignAdminAccountToNewProjectListener">
		<init-param>
			<param-name>accountId</param-name>
			<param-value>1 44</param-value><!-- user account IDs or user names separated by space or ';' character -->
		</init-param>
	</listener>
*/

/**
 * Assigns a list of accounts with "project admin" role to
 * a newly created project.
 *
 * @author <a href="mailto:zsolt.koppany@intland.com">Zsolt Koppany</a>
 */
public class AssignAdminAccountToNewProjectListener extends DefaultProjectListener {
	private final static ProjectManager projectManager = ProjectManager.getInstance();

	public void identifiableCreated(BaseEvent event) {
		if (event.isPreEvent()) {
			return;
		}

		UserDto user = event.getUser();
		ProjectDto project = (ProjectDto)event.getSource();
		GroupDto projectGroup = Acl.findGroup(project.getId().intValue(), GroupType.PROJECT);
		RoleDto projectAdminRole = Acl.findRole(RoleDto.PROJECT_ADMIN, projectGroup);

		String accountIds = getProperty("accountId");
		if (StringUtils.isNotBlank(accountIds)) {
			List users = new ArrayList();
			for (StringTokenizer st = new StringTokenizer(accountIds, " ;", false); st.hasMoreTokens(); ) {
				String accountId = st.nextToken().trim();

				UserDto account = Acl.findUser(accountId);

				if (account == null) {
					log.warn("Cannot find accountId: " + accountId);
					continue;
				}

				users.add(account);
			}

			try {
				projectManager.addUser(user, project.getId(), users, PersistenceUtils.createSingleItemList(projectAdminRole));
			} catch (Exception e) {
				log.warn("Assigning project admin failed", e);
			}
		}

		super.identifiableCreated(event);
	}
}

Checking Uploaded Documents for Viruses

A very useful extension of CodeBeamer is the addition of virus checking for documents. This check needs to be done at upload time for both document creation and update.

To do this the com.intland.codebeamer.event.ArtifactListener interface needs to be implemented. In this listener the both the identifiableCreated(BaseEvent event) and identifiableUpdated(BaseEvent event) methods need to call a virus checking routine. A dummy implementation of the method follows:

protected void checkArtifact(BaseEvent event) throws VetoException {
  Object source = event.getSource();

  if(source instanceof ArtifactDto) {
    ArtifactDto artifact = (ArtifactDto)source;

    // The 'v' character in the name signals a virus
    if(artifact.getName().toLowerCase().indexOf('v') != -1) {
      log.error(getClass() + " has detected a virus in file "
                           + artifact.getName());
      log.error("Upload aborted.");

      // Virus detected
      throw new VetoException();
    } else {
      // The file is fine
      log.info("Artifact successfully created for file "
               +artifact.getName());
    }
  } else {
    log.error("Invalid artifact object of type " + source.getClass());
  }
}

The ArtifactDto instance contains all the information related to the uploaded document. A simple check is being made regarding the occurence of the v character in the file name. Virus detection is signalled by throwing a VetoException instance.

Creating Tracker Item Validation Rules

The CodeBeamer Listener API can be used for implementing custom fine-grained validation rules for tracker items. In this section a rule is created for allowing the deletion of only the closed tracker items.

The TrackerItemListener interface suits this purpose. From this interface the identifiableDeleted(BaseEvent) method is overridden as follows:

public void identifiableDeleted(BaseEvent event) throws VetoException {
  try {
    Object source = event.getSource();

    if(source instanceof TrackerItemDto) {
      TrackerItemDto item = (TrackerItemDto)source;

      if(item.getStatus().getName() == null
         || !item.getStatus().getName().toLowerCase().equals("closed")) {
        log.info("Tracker item " + item.getId()
                 + " is not closed. Deletion aborted.");

        // Cannot delete an unclosed tracker item
        throw new VetoException();
      } else {
        // Tracker item can be deleted
        log.info("Tracker item "  + item.getId() + " successfully deleted.");
      }
    } else {
      log.warn("Invalid tracker object type " + source.getClass());
    }
  } catch(Exception ex) {
    // Make sure that all exceptions are caught
    throw new VetoException();
  }
}
The source of the event is a TrackerItemDto object. Unclosed tracker items are not allowed to be deleted by throwing a VetoException instance. As a safeguard, all exceptions are caught inside the handler method to not propagate any errors further.

Registering and Deploying Listeners

You can register listeners declaratively or programmatically.

Declarative Registration

This section explains how to register listeners in the CB_HOME/tomcat/webapps/cb/WEB-INF/classes/my-applicationContext.xml configuration file. This file configures the Spring Framework-managed beans that compose the application itself. If you want to know more about Spring and its bean factories, please read this page. If all you want to do is adding some custom listeners, you can skip reading that page, just read on here.

First you have to declare your listener bean:

<bean id="exampleListener" class="com.mycompany.cb.ExampleListener"></bean>
Make sure your class file is available on the classpath. Declarations can appear in any order, the file structure is flexible until it is kept a syntactically correct XML file.

CB-6.0 and older:

You also have to add your listener to the tail of this list:

<bean id="myListenerListFactory" parent="listenerListFactory">
  <property name="sourceList">
    <list merge="true">
      <!-- ... some other beans referenced here -->
      <ref bean="exampleListener"></ref>
    </list>
  </property>
</bean>

Finally, activate this bean declaration if this is commented out. Until this commented out (meaning that this is inactive), your other changes are ignored:
<bean id="eventMulticaster" class="com.intland.codebeamer.event.EventMulticaster" factory-method="getInstance" lazy-init="false" >
  <property name="listeners"><ref bean="myListenerListFactory"></ref></property>	
</bean>

CB-6.1 and newer:

Listeners declared in my-applicationContext.xml will be registered automatically.
You have to remove any old
  • <bean id="myListenerListFactory" ...> and
  • <bean id="eventMulticaster" ...>
entries from my-applicationContext.xml, otherwise CodeBeamer will not start at all!

When finished, don't forget to restart CB.

Migrating Listener Declarations from CB 5.5 (or Earlier) to CB 5.5.1 (or Later)

Prior to codeBeamer 5.5.1, listeners were registered in general.xml. For technical reasons, in all versions starting from 5.5.1 they are registered in my-applicationContext.xml, which also means that existing listener registrations needs to be converted. Converting the old-style declarations in general.xml to the new-style declarations in my-applicationContext.xml is fairly trivial, but here is a example to help your migration.

For each declaration like this in general.xml:

<listener id="myExistingListener" class="com.mycompany.cb.ExistingListener" />
...add its replacement to my-applicationContext.xml:
<bean id="myExistingListener" class="com.mycompany.cb.ExistingListener"/>

Then delete the original declaration from general.xml. You can actually delete the whole <listeners> group, as all listener need to be moved to my-applicationContext.xml.

Finally, uncomment the "eventMulticaster" bean in my-applicationContext.xml as it is written in the previous section.

Then restart CB and that's it!

Programmatic Registration

However the recommended way is using the declarative listener registration, it is possible to instantiate your listeners for yourself and register them using the following code snippet:

Listener myCustomListener = new MyCustomListener();
// …
EventMulticaster.getInstance().addListener(myCustomListener);
As you can see, EventMulticaster is a singleton in CodeBeamer, because to avoid confusion there must a single centralized event source in the system.

Listener Deployment

The binary code for the listeners has to be made available for the CodeBeamer installation. These are the two preferred ways for doing this: copy the class files to the <CodeBeamer Root>/tomcat/webapps/cb/WEB-INF/classes directory package the classes into a JAR file and place it in the <CodeBeamer Root>/tomcat/ webapps/cb/WEB-INF/lib directory In either case the classes will be automatically made available in the classpath. There are other ways of adding the listener classes to the classpath, however the above mentioned ones are recommended.

Frequently Asked Questions

  • What should I do in the event handlers that are insignificant for me, but which I am forced to implement?
You can simply leave those method bodies empty, it has no side-effects at all.
  • Can I safely override the default listeners shipped with CodeBeamer?
No. CodeBeamer relies on actively using its own listeners to implement several mechanisms. Disabling the default listeners might result in undefined behavior and data failure.
  • Is the order of the listeners calls defined by their list in general.xml?
No, there is absolutely no guarantee for which order they receive the notifications. Please don not rely on this.
  • If a listener vetoes an operation, will the other listeners get any kind of notification about this?

No. If the listeners are normally notified in this order A, B, C, D and B vetoes the operation, then:

  • A will not know that B vetoed it
  • C and D will not be called at all
This is a design decision to keep the behavior simple, but powerful enough for most real-life applications.

Adding Indexers to CodeBeamer

CodeBeamer indexes for search Excel, MS-Word, Power-Point, RTF, PDF, Html, xml, Wiki and Plain text documents and attachments.

Following steps must be executed to add additional Indexers:

A java class must implement the interface com.intland.codebeamer.search.handler.DocumentHandler and the Indexer must be added to /install_dir/tomcat/webapps/cb/WEB-INF/classes/general.xml to get it known for CodeBeamer.

The example below shows the plain-text Indexer assigned to the mime-type text/plain:

public class PlainTextHandler implements DocumentHandler {
	private String encoding = null;

	public Document getDocument(InputStream is) throws DocumentHandlerException {
		try {
			String body = Common.readFileToString(is, getEncoding());
			if (body != null && body.length() != 0) {
				Document doc = new Document();
				doc.add(new Field(Fields.BODY, body, Field.Store.NO, Field.Index.TOKENIZED));
				return doc;
			}
			return null;
		} catch (IOException e) {
			throw new DocumentHandlerException(e);
		}
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String enc) {
		encoding = StringUtils.trimToNull(enc);
	}
} 

The appropriate entry in general.xml:

<mime-mapping>
	<class>com.intland.codebeamer.search.handler.types.text.PlainTextHandler</class>
	<mime-type>text/plain</mime-type>
</mime-mapping>

The indexer class must be in CLASSPATH of CodeBeamer (for example under /install_dir/tomcat/webapps/cb/WEB-INF/classes) and after modifying general.xml Codebeamer must be re-started.