< 上一课 | 下一课 >

运行查询并显示结果集

下面这段示例代码是一个 Swing 应用程序,它执行以下操作: 通过 run 方法来选择和执行查询。 通过 showResults 方法来显示结果集。下面是完整的示例:
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)));
    
        // Convert the list to a sorted array for use in the selection dialog
        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()); }});
    
        // Present the list of queries to the user and allow the user to select one
        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);
        
        // If the query executed properly, save the data and prepare it for display
        if (results.hasNext()) {
            // Column information accessed from the viewer
            g_columns = results.getColumnLabels();
            g_cell = new CqRowData[(int)results.getRowCount()];
    
            for (CqRowData row: results)
                (g_cell[(int)row.getRowNumber()-1] = row).getValues();
            
            // Display the query result data
            showResults(query.location().string(), viewer);
        }
    }
    
    /** The result set made accessible to the GUI components for display */
    static CqRowData[] g_cell;
    /** The column headings made accessible to the GUI components for display */
    static String[] g_columns;
    
    /**
     * Displays the result set (in g_cell) in a table.
     * 
     * @param title The title string for the result set window
     * @param viewer A Viewer instance to be used for a detailed display of a
     *            single resource of the result set. May be null, in which case
     *            the option to display a single resource is not presented.
     */
    static void showResults(String title, final Viewer viewer) {
        // Define the table model for the JTable window; one column for each
        // query display field and one row for each row of the query result set.
        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]; }
        };
        
        // Construct the query result window with an optional button for
        // displaying the record in a selected row (used in the View Record and
        // Modify Record examples)
        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;
    }
    
    /**
     * A simple interface for an object that will display a Record resource.
     * (Used by extensions to the ExecuteQuery example.)
     */
    static interface Viewer {
        /**
         * Displays a Record resource
         * @param resource The Record proxy for the record to be displayed.
         * @return TODO
         */
        JFrame view(CqRecord resource);
    }
    
    /**
     * The main program for the ExecuteQuery example.
     * @param args Not used.
     * @throws Exception If a provider cannot be instantiated.
     */
    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);
        }
    }

在该示例中,按上一课程中所述构造可用数据库列表。向用户呈示该列表,以便用户从中选择一个数据库进行登录。

在用户选择用户数据库之后,应用程序会读入该数据库的 ALL_QUERIES 属性。该属性值为 CqQuery 代理的 ResourceList。该列表按查询位置进行排序,并向用户呈示该列表,以便用户从中选择某条查询来执行。

对于数据库和查询的选择,都采用了通用的 Swing 方法 - JOptionPane.showInputDialog。输入为从中进行选取的代理数组,结果则为选定的代理。代理 toString() 方法用于生成向用户显示的列表。代理的 toString() 方法生成了代理位置字段的映像,例如 Resource.location().string()。

由于会显示代理的位置,我们需要确保代理的位置便于用户查看,也就是说,代理的位置应该由分段的路径名组成,而不是由数据库标识组成。服务器可以自由选择代理返回的位置形式,一般来说,如果采用代理向服务器返回位置信息,那么服务器会选择处理效率最高的格式。最有效的格式往往不便于用户查看。任何情况下,客户机不应该臆断所采用的位置形式。所以,当我们请求数据库列表和查询列表时,我们还请求了列表中每一项的 USER_FRIENDLY_LOCATION 属性。然后,在 setUserFriendlyLocation 方法中,修改了每个代理的位置,使其采用便于用户查看的形式。

这个应用程序没有考虑所选查询定义了动态过滤器(也称为查询参数)这种可能性,如果所选查询有动态过滤器,那么这段代码会出现奇怪行为或者可能失败。更健全的实现应该在执行查询之前,向服务器请求查询的 DYNAMIC_FILTERS 属性并得到缺失的用户数据。这可以留给读者做练习。

请注意,对每一行都调用了 CqRowData.getValues(),因为 CqRowData 对象是放在数组中来显示的。必须要这样做,因为在释放 CqResultSet 迭代器之后,作为 Java™ 对象的用于计算行数据值的信息不可用,这在迭代器到达行尾之后自动会出现这种情况。

在这个代码样本中没有用到 ExecuteQuery.showResults 的第二个参数(指定的查看器),但是在下一个示例中会用到,用户用这个参数可以选择结果集中的行并显示相关记录。

课程检查点

现在,您已经了解了如何利用 Rational CM API 来运行查询,您可以自己查看可用的 Rational CM API 接口,并研究如何编写或修改现有的查询。
在本课程中,您已经了解了如何利用 Rational CM API 来运行查询。您学习到以下内容:
  • 运行 Rational ClearQuest 查询所需的 Rational CM API 对象。
  • 如何对结果集进行迭代。
  • 如何创建一个客户机应用程序来运行查询。
< 上一课 | 下一课 >

反馈