< Anterior | Próximo >

Executando uma consulta e exibindo o conjunto de resultados

O seguinte exemplo de código é um aplicativo Swing que executa as seguintes operações: A seleção e execução da consulta ocorre no método de execução. A exibição do conjunto de resultados ocorre no método showResults. Aqui está o exemplo completo:
static void run(String title, CqProvider provider, Viewer viewer)
    throws WvcmException
    {
        ResourceList<CqUserDb> databases =
            setUserFriendlyLocation(Utilities
                .getUserDbList(provider,
                               new PropertyRequest(CqUserDb.USER_FRIENDLY_LOCATION)));
        CqUserDb userDb = (CqUserDb)JOptionPane.showInputDialog
            (null, "Choose a Database to Explore", title, 
             JOptionPane.INFORMATION_MESSAGE, 
             null, databases.toArray(), databases.get(0));
    
        if (userDb == null) System.exit(0);
        
        userDb = (CqUserDb)userDb.doReadProperties
            (new PropertyRequest(CqUserDb.ALL_QUERIES.nest(CqQuery.USER_FRIENDLY_LOCATION)));
    
        // Converta a lista para uma matriz classificada para usar no diálogo de seleção
        CqQuery[] queries = 
            setUserFriendlyLocation(userDb.getAllQueries()).toArray(new CqQuery[]{});
    
        Arrays.sort(queries, new Comparator<CqQuery>(){
                public int compare(CqQuery arg0, CqQuery arg1)
                { return arg0.toString().compareTo(arg1.toString()); }});
    
        // Apresentar a lista de consultas para o usuário e permitir que o usuário selecione uma
        CqQuery query = (CqQuery)JOptionPane.showInputDialog
                    (null, "Choose a Query to Execute", 
                     "All Queries in " + userDb.location().string(), 
                     JOptionPane.INFORMATION_MESSAGE, null, 
                     queries, queries[0]);
        
        if (query == null) System.exit(0);
        
        CqResultSet results = 
            query.doExecute(1, Long.MAX_VALUE, CqQuery.COUNT_ROWS);
        
        // Se a consulta tiver sido executada adequadamente, salve os dados e prepare-os para exibição
        if (results.hasNext()) {
            // Informações da coluna acessadas a partir do visualizador
            g_columns = results.getColumnLabels();
            g_cell = new CqRowData[(int)results.getRowCount()];
    
            for (CqRowData row: results)
                (g_cell[(int)row.getRowNumber()-1] = row).getValues();
            
            // Exibir os dados do resultado da consulta
            showResults(query.location().string(), viewer);
        }
    }
    
    /** O conjunto de resultados que se tornou acessível aos componentes da GUI para exibição */
    static CqRowData[] g_cell;
    /** Os cabeçalhos da coluna que se tornaram disponíveis aos componentes da GUI para exibição */
    static String[] g_columns;
    
    /**
     * Exibe o conjunto de resultados (in g_cell) em uma tabela.
     * 
     * @param title A cadeia de título para a janela do conjunto de resultados
     * @param viewer Uma instância do visualizador a ser usada para uma exibição detalhada de um
     *            recurso único do conjunto de resultados. Pode ser nulo, caso no qual
     *            a opção para exibir um recurso único não é apresentada.
     */
    static void showResults(String title, final Viewer viewer) {
        // Definir o modelo de tabela para a janela JTable; uma coluna para cada
        // campo de exibição da consulta e uma linha para cada linha do conjunto de resultados da consulta.
        TableModel dataModel = new AbstractTableModel() {
    		 		 private static final long serialVersionUID = -3764643269044024406L;
    		 		 public int getColumnCount() { return g_columns.length; }
            public int getRowCount() { return g_cell.length;}
            public Object getValueAt(int row, int col) 
                { return g_cell[row].getValues()[col]; }
            public String getColumnName(int col)
                { return g_columns[col]; }
        };
        
        // Construir a janela de resultados da consulta com um botão opcional para
        // exibição de um registro em uma linha selecionada (usada nos exemplos Visualizar Registro e
        // Modificar Registro)
        final JFrame frame = new JFrame(title);
        final JTable table = new JTable(dataModel);
        JPanel panel = new JPanel(new BorderLayout());
        
        if (viewer != null) {
            JButton button = new JButton("Open");
    
            panel.add(button, BorderLayout.SOUTH);
            button.addActionListener(new ActionListener(){
                    public void actionPerformed(ActionEvent arg0)
                    {
                        int[] selected = table.getSelectedRows();
                        
                        for (int i = 0; i < selected.length; ++i)
                            try {
                                viewer.view((CqRecord) g_cell[selected[i]]
                                    .getRecord());
                            } catch (WvcmException e) {
                                Utilities.exception(frame, "View Record", e);
                            }
                    }
                });
        }
        
        panel.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(panel);
        frame.setBounds(300, 300, 600, 300);
        frame.setVisible(true);
    }
    
    static <U extends=""> ResourceList<U> 
    setUserFriendlyLocation(ResourceList<U> list)
    throws WvcmException
    {
        for (U res: list)
            res.modifyLocation(res.getUserFriendlyLocation());
    
        return list;
    }
    
    /**
     * Uma interface simples para um objeto que exibirá um recurso de Registro.
     * (Usado pelas extensões para o exemplo ExecuteQuery).
     */
    static interface Viewer {
        /**
         * Exibe um recurso de Registro
         * @param resource O proxy Recurso para o registro a ser exibido.
         * @return TODO
         */
        JFrame view(CqRecord resource);
    }
    
    /**
     * O principal programa para o exemplo ExecuteQuery.
     * @param args Não utilizado.
     * @throws Exception Se um fornecedor não puder ser instanciado.
     */
    public static void main(String[] args) throws Exception
    {
        try {
            run("Execute Query", Utilities.getProvider().cqProvider(), null);
        } catch(Throwable ex) {
            Utilities.exception(null, "Execute Query", ex);
            System.exit(0);
        }
    }

Neste exemplo, a lista de bancos de dados disponíveis é construída como na lição anterior. E a lista é apresentada ao usuário para seleção de um único banco de dados no qual se registrar.

Depois do usuário selecionar um banco de dados do usuário, a propriedade ALL_QUERIES desse banco de dados é lida no aplicativo. O valor desta propriedade é um ResourceList de proxies CqQuery. Esta lista é classificada no local da consulta e apresentada ao usuário para seleção de uma única consulta a executar.

Para seleção do banco de dados e seleção da consulta, o mesmo método de propósito geral Swing, JOptionPane.showInputDialog, é usado. A entrada é a matriz dos proxies dos quais selecionar e o resultado é o proxy selecionado. O método proxy toString() é usado para gerar a lista exibida para o usuário. O método toString() de um proxy gera uma imagem do campo do local do proxy, i.e. Resource.location().string().

Como o local do proxy está sendo exibido, precisamos nos certificar de que o local do proxy seja fácil e simples, isto é, composto de nomes de caminho segmentados ao invés de ids do banco de dados. Os servidores estão livres para usar qualquer forma de local nos proxies que eles retornem e, em geral, irão selecionar o formato que é processado mais eficientemente se o proxy for usado para retornar ao servidor. O formato mais eficiente é raramente fácil e simples. De qualquer forma, um cliente não deve supor qual forma de local é usada. Assim, quando solicitamos a lista do banco de dados e a lista de consulta, nós também solicitamos a propriedade USER_FRIENDLY_LOCATION de cada item da lista. Então, no método setUserFriendlyLocation, nós modificamos cada local do proxy com sua versão fácil e simples.

Este aplicativo ignora a possibilidade de que o proxy selecionado defina filtros dinâmicos (também chamados parâmetros de consulta) e irão exibir comportamento estranho ou, talvez, falhar se a consulta selecionada tiver filtros dinâmicos. Uma implementação mais robusta solicitaria a propriedade DYNAMIC_FILTERS da consulta do servidor e obter os dados ausentes do usuário antes de executar a consulta. Isso é deixado como um exercício para o leitor.

Observe que o CqRowData.getValues() é invocado em cada linha conforme o objeto CqRowData vai sendo colocado na matriz para exibição. Isso é necessário pois as informações necessárias para computar os valores de dados da linha como objetos de Java™ não estão disponíveis depois que o agente iterativo CqResultSet é liberado, o que ocorre automaticamente quando ele atinge o final.

O segundo parâmetro para o ExecuteQuery.showResults (denominado visualizador) não é usado nesta amostra, mas será usado no próximo exemplo para permitir que o usuário selecione uma linha do conjunto de resultados e exiba o registro associado.

Ponto de verificação da lição

Agora que você aprendeu como usar o Rational CM API para executar uma consulta, você pode revisar as interfaces disponíveis do Rational CM API sozinho e explorar como gravar ou modificar consultas existentes.
Nesta lição, você aprendeu como usar o Rational CM API para executar uma consulta. Você aprendeu o seguinte:
  • Sobre os objetos do Rational CM API necessários para executar uma consulta do Rational ClearQuest.
  • Como reiterar um conjunto de resultados.
  • Como criar um aplicativo do cliente que execute uma consulta.
< Anterior | Próximo >

Feedback