Getting the RTC User Work Environment Information


Recently I was asked how to access the users work environment information. This is basically the information displayed in the Work Environment Tab of the user editor.

User Work EnvironmentI was able to get at the Information. The code below shows how that works and what the information means.

Related code on this blog can be found in
Manage Scheduled Absences Using The PlainJava Client Libraries.

Please note, I looked briefly into ways to update that information, but I was not able to find any public interface to do so. I found internal methods that apparently do it, but not in a way that has an easy API provided to the user.

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!

You can download the latest version here: as Eclipse project.

Please note, there might be restrictions to access Dropbox and therefore 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 following code in this environment and get your own automation or extension working. The code linked from this post contains Client API.

Solution

The few methods below show how to access the data.

As usual, I use a very simple base class that connects to the repository and only performs the operations needed to get at the data. Please look at the downloadable code, if you are not sure how all that works together.

The specific API for the data in question is in the packages.

 com.ibm.team.apt.common,
 com.ibm.team.apt.client

The run() method below is called with all the parameters needed and basically connects to the team repository. It then finds the user it should look at based on the ID provided.

Next it gets the IResourcePlanningClient client library, and from that the ResourcePlanningManager which provides access to the data we are interested in.

The data we want is stored in the IContributorInfo that is returned by the call to the method getContributorInfo() providing the contributor object for the user we are interested in.

The data of interest is in the IWorkLocationDefinition available from the IContributorInfo. The code gets the information and then evaluates the details to print them.

private static boolean run(String[] args) throws TeamRepositoryException {

	if (args.length != 4) {
		System.out
				.println("Usage: GetWorkLocationAndWorkDayDetail    ");
		return false;
	}

	String repositoryURI = args[0];
	final String userId = args[1];
	final String password = args[2];
	String userToLookup = args[3];
	IProgressMonitor monitor = new NullProgressMonitor();

	ITeamRepository teamRepository = TeamPlatform
			.getTeamRepositoryService().getTeamRepository(repositoryURI);
	teamRepository
			.registerLoginHandler(new LoginHandler(userId, password));
	teamRepository.login(monitor);
		
	// Get the user to look at
	System.out.println("Data for user: " + userToLookup + ".");
	IContributor inspectUser = teamRepository.contributorManager()
			.fetchContributorByUserId(userToLookup, monitor);
		
	// Get the resource planning client 
	final IResourcePlanningClient resourcePlanning = (IResourcePlanningClient) teamRepository
			.getClientLibrary(IResourcePlanningClient.class);

	// Get the contributor related planning information
	IContributorInfo info = resourcePlanning.getResourcePlanningManager()
			.getContributorInfo(inspectUser, true, monitor);
		
	// Get the worklocation information that contains the working days
	IWorkLocationDefinition location = info.getWorkLocation(inspectUser);
	printWorkLocation(location);
	printWorkDays(location);

	teamRepository.logout();

	return true;
}

First it prints the work location information, basically the user environment information with the timezone and the regional settings.

There is some data “Variant” I am not sure it is used.

/**
 * Print the work location data
 * This includes the available location with timezone
 * 
 * @param location
 */
private static void printWorkLocation(IWorkLocationDefinition location) {
	System.out.println("Location");
	System.out.println("Language: " + location.getLanguage());
	System.out.println("Timezone: " + location.getTimeZone());
	System.out.println("ZoneOffset: " + location.getZoneOffset());
	System.out.println("Country: " + location.getCountry() + " not used");

	// Not used
	System.out.println("Variant: " + location.getVariant() + " not used");
}

Then the code prints the work day information.

/**
 * Print all work days for a users location
 * 
 * @param location
 */
private static void printWorkDays(IWorkLocationDefinition location) {
	System.out.println("\nWorkdays");
	Collection workDays = location.getWorkDays();
	for (IWorkDayDefinition workDay : workDays) {
		printWorkDay(workDay);
	}
}

private static int HOUR_IN_MILLISECONDS=60*60*1000;

/**
 * Print the work day data
 * 
 * @param workDay
 */
private static void printWorkDay(IWorkDayDefinition workDay) {
	int hour = HOUR_IN_MILLISECONDS;
	System.out.println("WorkDay: " + workDay.getDay().getName()
			+ " Literal " + workDay.getDay() + ".");
	System.out
			.println("\tWorking time: " + workDay.getWorkingTime()
					+ " milliseconds equals to " + workDay.getWorkingTime() / hour
					+ " hours");
	System.out.println("\tEndTime " + workDay.getEndTime()
			+ " milliseconds equals to " + workDay.getEndTime() / hour + " hour.");
}

The interesting information here is in the interface IWorkDayDefinition.

  • The day returned by getDay() as IWeekDay which provides the day information using a label and a name; label and name are a string
  • The working time (how many hours a day) for each day using getWorkingTime()
  • The time when the user stops working using getEndTime()

Both time values are provided in milliseconds. The working time is the time in hours set in milliseconds. The end time is the end time in milliseconds from midnight.
Running the code with parameters

"https://clm.example.com:9443/ccm/" "admin" "*****" "curtis"

results in the following output (for the same user shown in the image at the beginning):

Data for user: curtis.
Location
Language: en
Timezone: US/Eastern
ZoneOffset: -18000000
Country: US
Variant: null not used

Workdays
WorkDay: MONDAY Literal MONDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 64800000 milliseconds equals to 18 hour.
WorkDay: TUESDAY Literal TUESDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: WEDNESDAY Literal WEDNESDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: THURSDAY Literal THURSDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: FRIDAY Literal FRIDAY.
	Working time: 28800000 milliseconds equals to 8 hours
	EndTime 61200000 milliseconds equals to 17 hour.
WorkDay: SATURDAY Literal SATURDAY.
	Working time: 0 milliseconds equals to 0 hours
	EndTime 0 milliseconds equals to 0 hour.
WorkDay: SUNDAY Literal SUNDAY.
	Working time: 0 milliseconds equals to 0 hours
	EndTime 0 milliseconds equals to 0 hour.

Summary

This post provides you with all the code and information needed to read and interpret the WorkLocation information stored in RTC.

As always, I hope this post saves users out there some time – or is at least fun to read.

Advertisements

Manage Scheduled Absences Using The PlainJava Client Libraries


I have seen questions in the Jazz.net forum around how to manage public holidays or other scheduled absences for a large user base. I have heard this kind of questions from others as well. And thought a solution would be quite interesting, so here goes.

Since I hate repetitive, boring, time consuming tasks as any one else, I wanted to do something about this for a while. In the context of this question two colleagues from Japan, Saitoh-san and Kobayashi-san approached me. They already had created a solution but were not sure how to publish it. They invited me into their IBM DevOps Services project to share what they had done. I looked into the code and found they had actually implemented an Eclipse Wizard to import scheduled absences for a user.

Since I can’t blog about things I haven’t done, I decided to take a deeper look at what they had done and create a solution from there. I finally ended up creating some tooling that allows to manage single absences and collections of scheduled absences for one or many users.

This image shows the scheduled absences added to a user.

Absences

The code in this post is client API.

This blog post uses internal API which can be changed at any time.

This blog post uses internal API which can be changed at any time. If the Internal API changes, the code published here will no longer work.

Warning, some of the code uses internal API that might change in the future. If the Internal API changes, the code published here will no longer work.

The code in this post hides the RTC API for scheduled absences, which is actually an internal API, from the user. It provides methods to conveniently work with absences. It allows to create, read and delete absences for one or many users. Before we continue, the usual ceremony:

License

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!

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 following code in this environment and get your own automation or extension working.

The Code

The code discussed in this post can be downloaded from here. Please note, the code might change over time, although I hope to keep the interfaces stable.

 The Absence Manager Overview

The source code of the Absence Manager is separated into three projects. The core project com.ibm.js.team.admin.automation.absence.core contains all the code required to create tooling to manage absences.

Core Absence Manager Project

Core Absence Manager Project

The package with suffix core contains the interfaces to work with, for most of the time.

  • IAbsence represents the Interface to scheduled absences in an external format used to store the data in a common format  and to make the data accessible
  • IAbsenceFactory is an interface that provides ways to create scheduled absences in the external format in different ways; the pattern to convert strings and timestamps can be set in the constructor; see the section Date, Timestamp and String Representation Troubles – Here be Dragons below
  • IAbsenceManager is an interface that the Absence Manager provides to allow to create, read and delete absences; it uses an IAbsenceFactory to create absence objects where needed

The package with suffix impl contains implementations for the interfaces that do the real work.

The package with suffix utils contains a utility class that basically manages the conversion of timestamps and string representations.

I ended up with this structure, because I wanted clear abstractions of the concepts and allow to easily enhance or replace the implementations if one so desires. Before I finally ended up with this clear structure, there where a lot of inter-dependencies in the code that where hard to handle. They tended to break the code when introducing small changes and where very confusing in general.

This is by far the most complex automation I blogged about so far and I needed to be able to test it during refactoring. Once I had the first snippets available I used a test driven approach to finalize the solution. This also made the whole refactoring required to get to a clean structure possible in the first place.

The project com.ibm.js.team.admin.automation.absence.core.tests contains unit test for the core classes and interfaces. The unit tests should cover most of the interface and its implementation. I did not make sure all is covered, but the main functionality should be covered.

  • AbsenceDataTest basically runs some simple tests to create absences in different formats
  • AbsenceManagerTest runs tests against a test repository and manages test scheduled absences in that repository for the logged in user testing, leaving the user with no scheduled absences
  • AllTests is a suite that runs all tests above

The third project com.ibm.js.team.admin.automation.absence.csv basically has two classes, that implement CSV import and -export of scheduled absences for all active (not archived) users.

CSV Absence Manager

CSV Absence Manager

The classes can be used as prototype for a custom implementation.

To read and write CSV files I used opencsv to avoid having to implement CSV reading and writing. This made it very easy to implement the functionality after the fundamental interfaces where working.

NOTE: I will not include opencsv in the download. You can download it from sourceforge, unzip it and place the library in the lib folder of the project.

There are other open and free Java implementations of CSV file readers for example SuperCSV for download as well.

  • ScheduledAbsenceCSVImporter uses a CSV file with a comma separated format to read scheduled absences and adds them to all users that are not archived
  • ScheduledAbsenceCSVExporter exports all scheduled absences for all active users to a CSV file, with a similar format, except it contains the user ID as a leading column

Here an example file for using as import source:

CSV Import Example File

CSV Import Example File

Other Uses of the AbsenceManager

If  you have a common system with an Interface to get at absence data, you can create an integration to that system with the attached code. Such an integration could, as an example, synchronize the absences between the other system and Rational Team Concert servers. The simplest approach would be to always delete all absences for a user in RTC and then recreate the absences from that system. This could be done in a nightly run.

RTC, Absences and the AbsenceManager

RTC stores the absences as java.sql.Timestamps in the CCM databse. Absences basically have the following data:

  • Summary – a text that describes the absence
  • StartDate – a Timestamp of the start date
  • EndDate – a Timestamp of the end date, the same as the start date in case of one day long absences

Absences are defined by the three attributes. To be able to find absences it is necessary to find one with the same summary and the same dates. While developing the Absence Manager, it became apparent that matching for the exact data is sometimes not desirable. Therefore the date is, in some cases, only compared to the same day, to avoid missing matches. For the summary the match is implemented as ignore-case.

It would be easy to implement a way to find all absences by the summary. This would potentially be a collection of items. For the use cases so far it was not necessary to implement it and thus I left it out.

During testing, when absences are manually created, the time created for the absence seemed to be 2pm in the timezone of the server. While specifying the absence the user actually only selects the date and not the time. If using automation, first check what the server would create and specify the times accordingly.

The RTC Absence API

The API to get absences is very easy. The code below shows how to access the scheduled absences for a contributor. All the code is hidden in the AbsenceManagerImpl.

	/**
	 * Get the internal representation of all absences of a contributor.
	 * 
	 * @param contributor
	 * @param monitor
	 * @return
	 * @throws TeamRepositoryException
	 */
	private ItemCollection getContributorAbsences(
			IContributorHandle contributor, IProgressMonitor monitor)
			throws TeamRepositoryException {
		final IResourcePlanningClient resourcePlanning = (IResourcePlanningClient) fTeamRepository
				.getClientLibrary(IResourcePlanningClient.class);

		IContributorInfo info = resourcePlanning.getResourcePlanningManager()
				.getContributorInfo(contributor, true, monitor);
		ItemCollection absences = info
				.getAbsences(contributor);
		return absences;
	}

The code basically gets the IResourcePlanningClient to get the ResourcePlanningManager and uses this to get the IContributorInfo. This contains the absences as as well as the team allocations.  The call .getAbsencs(IContributorHandle) returns an ItemCollection with all the IContributorAbsences. All the classes and interfaces, except IContributorAbsence are internal API. This is the reason why it should be encapsulated so that most of the implementation does not interfere with it. This will make it easier to adjust to changing API’s later.

The code below shows how to create a IContributorAbsence

	/**
	 * Create an internal IContributorAbsense from an IAbsence 
	 * 
	 * @param contributor
	 * @param iAbsence
	 * @return
	 */
	private IContributorAbsence createContributorAbsence(
			IContributorHandle contributor, IAbsence iAbsence) {
		ContributorAbsence absence = (ContributorAbsence) IContributorAbsence.ITEM_TYPE
				.createItem();
		absence.setContributor(contributor);
		absence.setSummary(iAbsence.getSummary());
		absence.setStartDate(iAbsence.getStartDate());
		absence.setEndDate(iAbsence.getEndDate());
		return absence;
	}

The data provided during creation is String and timestamps. Please note, this class is not part of the plain java client libraries but shipped with the RTC Eclipse client plugins in the file com.ibm.team.apt.common_*.jar. You need to add this jar file to your classpath, if you run this outside of the RTC SDK as described below.

This code shows how new absences are saved using saveAbsences().

	/**
	 * Add absences from a collection to a user using the contributor object of
	 * the user. The method checks if an absence with the same summary, same
	 * start- and end- date already exist. The comparison converts the dates and
	 * uses a precision of a day to find matches.
	 * 
	 * @throws TeamRepositoryException
	 */
	@Override
	public void addAbsences(IContributorHandle contributor,
			Collection absences, IProgressMonitor monitor)
			throws TeamRepositoryException {
		final IResourcePlanningClient resourcePlanning = (IResourcePlanningClient) fTeamRepository
				.getClientLibrary(IResourcePlanningClient.class);

		List absencesToBeCreated = new ArrayList();

		IContributorInfo info = resourcePlanning.getResourcePlanningManager()
				.getContributorInfo(contributor, true, monitor);
		/**
		 * Can't access all absences, need to narrow down to contributor
		 */
		ItemCollection existingAbsences = info
				.getAbsences(contributor);

		for (Iterator iterator = absences.iterator(); iterator
				.hasNext();) {
			IAbsence iAbsence = (IAbsence) iterator.next();

			/**
			 * Check if the absence is already there to avoid entering it
			 * multiple times. The check is for an match of all data. It does
			 * not prevent from entering absences that overlap or different
			 * summaries. The check of the dates is not precise, but on a day
			 * level.
			 */
			if (!exists_SameDay(existingAbsences, iAbsence)) {
				IContributorAbsence absence = createContributorAbsence(
						contributor, iAbsence);
				absencesToBeCreated.add(absence);
			}
		}
		resourcePlanning.saveAbsences(absencesToBeCreated
				.toArray(new ContributorAbsence[absencesToBeCreated.size()]),
				monitor);
	}

The code for removing absences is similar, only the call is to a different method – deleteAbsences().

	/**
	 * Remove a collection of absences from the absences. Matches by summary, as
	 * well as start- and end- date. Date match is don one a same-day basis.
	 * 
	 * @param contributor
	 *            contributor to remove absences from, must not be null.
	 * @param absences
	 *            collection of absences, must not be null.
	 * @param monitor
	 * @throws TeamRepositoryException
	 */
	@Override
	public void removeAbsences(IContributorHandle contributor,
			Collection absences, IProgressMonitor monitor)
			throws TeamRepositoryException {
		Assert.isNotNull(contributor);
		Assert.isNotNull(absences);
		final IResourcePlanningClient resourcePlanning = (IResourcePlanningClient) fTeamRepository
				.getClientLibrary(IResourcePlanningClient.class);

		List absencesToBeRemoved = new ArrayList();

		IContributorInfo info = resourcePlanning.getResourcePlanningManager()
				.getContributorInfo(contributor, true, monitor);
		/**
		 * Can't access all absences, need to narrow down to contributor
		 */
		ItemCollection existingAbsences = info
				.getAbsences(contributor);

		// For all absences
		for (Iterator iterator = absences.iterator(); iterator
				.hasNext();) {
			IAbsence iAbsence = (IAbsence) iterator.next();

			// search if the absence is available (match same day)
			IContributorAbsence found = findContributorAbsence(
					existingAbsences, iAbsence);
			if (null != found) {
				absencesToBeRemoved.add(found);
			}
		}
		IContributorAbsenceHandle[] remove = absencesToBeRemoved
				.toArray(new IContributorAbsenceHandle[absencesToBeRemoved
						.size()]);
		resourcePlanning.deleteAbsences(remove, monitor);
	}

That’s it. Nothing big. But….

The Rest of the Code

All the 9/10th rest of the code is basically to make it easy and convenient to manage the scheduled absences and to hide the internal API within. In addition tests and usage examples make up a reasonable amount of the code.

Date, Timestamp and String Representation Troubles – Here be Dragons

The biggest trouble in the whole implementation was the conversion of date and time to timestamps. This occurs in several areas. The general problem here is that there is no general tool that is able to parse any string defining a date/time without problems.

To overcome this, the AbsenceManager uses java.text.SimpleDateFormat. This requires a string expression to parse and map the external data to the internal representation.

By default the mapping pattern used is “yyyy/MM/dd hh:mm:ss z”. However, this requires to provide date, time and timezone. If it is necessary, e.g. to avoid the time and timezone, a different mapping string can be used. To provide a different mapping string, use the second constructor of the AbsenceFactoryImpl and provide the mapping string as shown below.

		new AbsenceFactoryImpl("yyyy/MM/dd")
		IAbsenceManager absenceManager= new AbsenceManagerImpl(teamRepository, new AbsenceFactoryImpl("yyyy/MM/dd"));

Please note, if no time is provided, the server will pick an hour on its own.

The IAbsenceFactory provides also ways to create new absence instances with different representations. However, keep in mind that some comparisons are done internally and it is best to have a common schema.

How to use the AbsenceManager

How to use the absence manager is shown in the classes AbsenceManagerTest and ScheduledAbsenceCSVImporter.  You have to be connected to a team repository with a user that has sufficient permissions to read/write the absences.

To get the AbsenceManager use:

		IAbsenceManager manager = new AbsenceManagerImpl(fTeamRepository,new AbsenceFactoryImpl());

		String absence1Summary="Absence 1";
		Date today= new Date();
		IAbsence absence1= manager.getAbsenceFactory().newInstance(absence1Summary, today);
		IAbsence absence1_sameday= manager.getAbsenceFactory().newInstance(absence1Summary, new Timestamp(today.getTime()+60000));
		IAbsence absence2= manager.getAbsenceFactory().newInstance(absence1Summary, "2014/07/17 02:00:00 CEST");
		IAbsence absence3= manager.getAbsenceFactory().newInstance(absence1Summary, "2014/07/17 02:00:00 CEST", "2014/07/30 02:00:00 CEST");

You can add single or multiple absences like this:

		// Add a single absence using a contributorHandle
		manager.addAbsence(contributorHandle, absence1, monitor);
		// Add a collection of absences
		ArrayList addAbsences= new ArrayList();
		addAbsences.add(absence1);
		addAbsences.add(absence2);
		manager.addAbsences(contributorHandle, addAbsences, monitor);

		// Add a single absence using a userId
		manager.addAbsence(manager.getContributor("ralph"), absence1, monitor);
		// Add a collection of absences
		ArrayListaddAbsences= new ArrayList();
		addAbsences.add(absence1);
		addAbsences.add(absence2);
		manager.addeAbsences(manager.getContributor("ralph"), addAbsences, monitor);

The interface implements a convenience method getContributor(String userID) to allow to get the IContributor interface, which also implements IContributorHandle, from the userId.

You can get absences for a user.

		ArrayList userAbsences=manager.getAbsences(contributorHandle, monitor);

You can test for an existing absence

		if(manager.hasAbsences(contributorHandle, absence1, monitor)){

You can remove specific absences

		manager.removeAbsence(contributorHandle, absence3, monitor);
		manager.removeAbsence(contributorHandle, absenceCollection, monitor);

You can delete all absences up to a specific date for

		// Clear all absences for user
		manager.purgeAbsences(contributorHandle, null , monitor);
		// Clear all absences up to a certain date for user
		manager.purgeAbsences(new Date(), monitor);
		// Clear all absences for all users up to a certain date (including archived users)
		manager.purgeAbsences(new Date(), monitor);
		// Clear all absences for all users (including archived users)
		manager.purgeAbsences(null, monitor);

Import the code

The code can be downloaded here. Save the code on the local disk. Set up an Eclipse client for example the RTC Eclipse client. Follow the section Setting Up The Plain Java Client Libraries and Setting Up Your Workspace for Plain Java Development in the post Setting up Rational Team Concert for API Development to set up at least the Plain Java Client Libraries. You don’t have to set up the SDK to run the code. This step would however provide you with access to the API classes and their source code. Make sure to create the user Library for the Plain Java Client Libraries.

Import the compressed file as archived project file into Eclipse.

Open CSV

The example does not ship the opencsv library. Download it by following the link e opencsv  and clicking on the download link in the General section of the description shown below.

Open CSV download link

Open CSV download link

Store the download file e.g. opencsv-2.3-src-with-libs.tar.gz in a temporary folder. Use 7Zip to extract the file. Use 7Zip again to extract the file content. Find the folder deploy in the extracted folder structure. E.g. C:\temp\opencsv-2.3\deploy  and copy the enclosed JAR file e.g. named opencsv-2.3.jar into the folder lib underneath the project com.ibm.js.team.admin.automation.absence.csv. Please note, opencsv also ships the file junit.jar. that is not the file you want.

IContributorAbsence

The planning component does not contribute any files to the plain Java Client Libraries. Unfortunately the interface com.ibm.team.apt.common.resource.IContributorAbsence that is used is part of that API. Similar to the opencsv jar file, find the files com.ibm.team.apt.common_*.jar and com.ibm.team.apt.client_*.jar in the Eclipse Plugins folder of an RTC Eclipse client installed from a zip file. If you install RTC with Installation Manager the files might be located in a shared folder.

Find the file com.ibm.team.apt.common_*.jar and com.ibm.team.apt.client_*.jar for your version of RTC and add it to the classpath e..g. by copying it into the plain Java Libraries folder.

For all the projects you just imported starting with com.ibm.js.team.admin.automation.absence.core. Run a clean build and check the build path for errors.  If you used the proposed name PlainJavaApi, for the Plain Java Client Libraries user library you should be fine. If you see errors, you probably have a different name. In this case configure the build path. Remove the Plain Java Client Library user library from the build path and add your user library.

Finally all errors should be gone.

Run the ScheduledAbsence Code

You are now ready to use the code and run the Unit Tests, the CSV importer and the CSV exporter.

The code ships with launches. They are located in a sub folder named Launches in the projects.The launches should now be available in the Eclipse Debug Configurations and Run Configurations menu.

Open the configuration e.g. for the ScheduledAbsenceCSVImporter launch. The Arguments tab will show

"https://clm.example.com:9443/ccm/" "ralph" "ralph" "USFederalHolidays2014.csv"

The  ScheduledAbsenceCSVImporter  and the ScheduledAbsenceCSVExporter require

  • the Repository URL
  • a user ID
  • a password
  • a name for the CommaSeperatedFile

Replace the information with your own values. Then you can run the importer and the exporter.

The same information is required in the AbsenceManagerTest Junit test. It is hard coded in the AbsenceManagerTest. Replace the values with your own information if you intent to run the test against you own test system.

This image shows the result of a run:

ImportOutput

Next Steps

I will try to find some time to be able to create a version that can be shipped as binaries with batches so that they can easily be run from the command line. In general the post Understanding and Using the RTC Java Client API should give you all the information you need to get this done yourself.

Summary

This post provides you with all the code and information needed to automate managing scheduled and other absences in RTC repositories. The code is obviously not production code, so you should make sure it works as advertized in your environment. the provided tests should help you to fix errors, should they occur.

As always, I hope this post saves users out there some time – or is at least fun to read.