O objeto do Provedor implementa a interface com o StpProvider e, desta maneira, conecta as outras interfaces do CM API para a implementação fornecida pela biblioteca do CM API.
Há duas classes de implementação do Provedor dentro da biblioteca do CM API; uma implementando a interface do CcProvider e uma implementando a interface do CqProvider. A classe de implementação do CqProvider é denominada pelo literal CqProvider.CQ_ONLY_PROVIDER_CLASS. Passe este para o método ProviderFactory.createProvider para obter uma instância da classe CqProvider do Rational CM API.
Também é necessário fornecer um objeto de Retorno de Chamada ao ProviderFactory.createProvider a partir do qual o Provedor instanciado possa obter objetos de Autenticação. O objeto de Autenticação fornece credenciais ao provedor necessárias para autenticar o usuário como um usuário do Rational ClearQuest antes de executar as operações em um banco de dados (como alterar o estado de um registro ou modificar valores de campo). O uso de um objeto de Retorno de Chamada que você fornecer dá um controle integral a seu aplicativo na aquisição de credenciais do usuário (nome de usuário e senha), que podem ser explicitamente configurados no aplicativo, solicitados do usuário na inicialização ou da primeira vez que seja necessário.
Como um objeto do Provedor é necessário para todos os casos de uso de programação com o Rational CM API, todos os exemplos deste tutorial usam um método getProvider definido na classe Utilitários a ser usada por todos os aplicativos. O objeto de Retorno de Chamada, também definido na classe Utilitários, solicita nome de usuário e senha quando o usuário tenta acessar um banco de dados e, em seguida, continua a reutilizar essas credenciais até quando forem aceitáveis.
/**
* Um objeto de Autenticação simples no qual o nome de usuário e senha
* obtidos do usuário são armazenados em cache para uso pela API da Equipe.
*/
static class UnPw implements Authentication {
/**
* Constrói um objeto de Autenticação
*
* @param unpw A String[] contendo um nome de usuário e senha.
*/
UnPw(String[] unpw) { m_data = unpw; }
public String loginName() { return m_data[0]; }
public String password() { return m_data.length > 1 ? m_data[1] : ""; };
/** As credenciais armazenadas em cache */
private String[] m_data;
}
/**
* Constrói uma instância de um provedor API do CM para ClearQuest.
*
* @return O objeto CqProvider instanciado
* @throws Exceção
* Se o provedor não puder ser instanciado
*/
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
{
// Tente reutilizar as últimas credenciais em cada novo repositório
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;
}
}
Neste exemplo nós usamos uma instância da interface do StpProvider.StpCallback estendida, porque são fornecidas mais informações quando a autenticação é solicitada.
Como o Rational CM API relata todos os erros lançando um StpException, nós incluímos na classe Utilitários um método que formata as informações de tal exceção em uma mensagem de texto e exibe-a em um diálogo Swing.
/**
* Extrai o conteúdo da mensagem de um Throwable e retorna-o como uma
* matriz hierárquica de Cadeias capturando o aninhamento dos componentes de mensagem Throwable.
* Esta estrutura formata razoavelmente em uma invocação SWING
* showMessageDialog.
*
* @param ex O objeto Throwable cujo conteúdo de mensagem deve ser extraído.
* @return Se o Throwable dado tiver componentes aninhados, uma matriz que consiste na
* mensagem do Throwable e uma matriz das mensagens aninhadas.
*/
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;
}
/**
* Exibe um diálogo Swing contendo as mensagens associadas com um
* Throwable dado.
*
* @param frame O quadro pai para o diálogo da mensagem.
* @param title O título a aparecer na janela de diálogo.
* @param ex O throwable cujas mensagens devem ser exibidas.
*/
static void exception(Component frame, String title, Throwable ex) {
JOptionPane.showMessageDialog(frame,
messages(ex),
title,
JOptionPane.ERROR_MESSAGE);
}