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 CM API 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); }