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 的第二个参数(指定的查看器),但是在下一个示例中会用到,用户用这个参数可以选择结果集中的行并显示相关记录。