Getting a Provider
About this task
The Provider object implements the StpProvider interface and thereby connects the other CM API interfaces to the implementation provided by the CM API library.
The CqProvider implementation class is named by the literal CqProvider.CQ_ONLY_PROVIDER_CLASS. Pass this to the ProviderFactory.createProvider method to obtain an instance of the Rational ClearQuest CM API CqProvider class.
ProviderFactory.createProvider also needs to be given a Callback object from which the instantiated Provider can obtain Authentication objects. The Authentication object provides the provider with the credentials needed to authenticate the user as a Rational ClearQuest user before performing operations in a database (such as changing the state of a record or modifying field values). The use of a Callback object that you supply gives your application full control over the acquisition of user credentials (username and password), which may be explicitly set into the application, solicited from the user on start up, or the first time it is needed.
Since a Provider object is needed for all use cases of programming with the Rational ClearQuest CM API, all of the examples in this tutorial use a getProvider method defined in the Utilities class to be used by all applications. The Callback object, also defined in the Utilities class, requests user name and password when the user first tries to access a database and then continues to reuse those credentials as long as they are acceptable.
/**
* A simple Authentication object in which the username and password
* obtained from the user is cached for use by the Rational
ClearQuest CM API.
*/
static class UnPw implements Authentication {
/**
* Constructs an Authentication object
*
* @param unpw A String[] containing the username and password.
*/
UnPw(String[] unpw) { m_data = unpw; }
public String loginName() { return m_data[0]; }
public String password() { return m_data.length > 1 ? m_data[1] : ""; };
/** The cached credentials */
private String[] m_data;
}
/**
* Constructs an instance of a CM API provider for Rational
ClearQuest.
*
* @return The instantiated CqProvider object
* @throws Exception
* If the provider could not be instantiated
*/
static StpProvider getProvider() throws Exception {
try {
Callback callback = new StpCallback() {
private UnPw m_unpw;
public Authentication getAuthentication(String r, int c)
{ return null; /* Will not be called */ }
public Authentication getAuthenticationEx(Domain domain,
String realm,
int retryCount,
StpProvider provider,
WvcmException failure)
throws WvcmException
{
// Try to reuse last credentials on each new repository
if (m_unpw != null && retryCount == 0)
return m_unpw;
String title = "Enter " + domain
+ " Username '+' Password for "
+ realm + " [" + retryCount + "]";
if (failure != null)
title = "Login failed: " + failure + "\n" + title;
String unpw = JOptionPane.showInputDialog(title, "admin+");
if (unpw == null || unpw.length() == 0)
throw new IllegalAccessError("User canceled request");
if (unpw.equals("anonymous"))
return null;
if (unpw.startsWith("@")) {
File file = new File(unpw.substring(1));
try {
FileReader reader = new FileReader(file);
char[] buf = new char[100];
int count = reader.read(buf);
unpw = new String(buf, 0, count);
reader.close();
} catch (Throwable t) {
Utilities.exception(null,
"Reading password file " + unpw,
t);
}
}
return m_unpw = new UnPw(unpw.split("\\+", -2));
}
};
// Instantiate a Provider
return (StpProvider) ProviderFactory
.createProvider(StpProvider.PROVIDER_CLASS, callback);
} catch (InvocationTargetException ite) {
WvcmException e = (WvcmException) ite.getTargetException();
System.out.println("*** " + e);
for (Throwable nested: e.getNestedExceptions())
System.out.println("*** " + nested);
throw e;
}
}
In this example we use an instance of the extended StpProvider.StpCallback interface because it is provided more information when authentication is requested.
Since the Rational ClearQuest CM API reports all errors by throwing an StpException, we include in the Utilities class a method that formats the information in such an exception into a text message and displays it in a Swing dialog.
/**
* Extracts the message content from a Throwable and returns it as a
* hierarchical array of Strings capturing the nesting of the Throwable's
* message components. This structure formats reasonably in a SWING
* showMessageDialog invocation.
*
* @param ex The Throwable object whose message content is to be extracted.
* @return If the given Throwable has nested components, an array consisting
* of the Throwable's message and an array of the nested messages.
*/
private static Object messages(Throwable ex) {
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0)
msg = ex.toString();
if (ex instanceof StpException) {
Throwable[] nested = ((StpException) ex).getNestedExceptions();
if (nested != null && nested.length > 0) {
Object[] msgs = new Object[nested.length];
for (int i = 0; i < msgs.length; ++i)
msgs[i] = messages(nested[i]);
return new Object[] { msg, msgs };
}
} else if (ex.getCause() != null) {
return new Object[] {msg, new Object[]{messages(ex.getCause())}};
}
return msg;
}
/**
* Displays a Swing dialog containing the messages associated with a given
* Throwable.
*
* @param frame The parent frame for the message dialog.
* @param title The title to appear in the dialog window.
* @param ex The throwable whose messages are to be displayed.
*/
static void exception(Component frame, String title, Throwable ex) {
JOptionPane.showMessageDialog(frame,
messages(ex),
title,
JOptionPane.ERROR_MESSAGE);
}
Results
Lesson checkpoint
- About Callback objects
- About Provider objects
- About exception handling in Rational ClearQuest CM API
- How to use the Rational ClearQuest CM API to instantiate Callback and Provider objects
- How to use the Rational ClearQuest CM API for exception handling