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))); // 將清單轉換成選項對話框中使用的排序陣列 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()); }}); // 將查詢清單呈現給使用者並容許使用者選取其中之一 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 (results.hasNext()) { // 從檢視器存取的直欄資訊 g_columns = results.getColumnLabels(); g_cell = new CqRowData[(int)results.getRowCount()]; for (CqRowData row: results) (g_cell[(int)row.getRowNumber()-1] = row).getValues(); // 顯示查詢結果資料 showResults(query.location().string(), viewer); } } /** 結果集可供 GUI 元件存取並予以顯示 */ static CqRowData[] g_cell; /** 直欄標題可供 GUI 元件存取並予以顯示 */ static String[] g_columns; /** * 在表格中顯示結果集(在 g_cell 中)。 * * @param title 結果集視窗的標題字串 * @param viewer 用於詳細顯示結果集的單一資源 * 的 Viewer 實例。可能是空值,如果是這樣, * 不會呈現顯示單一資源的選項。 */ static void showResults(String title, final Viewer viewer) { // 定義 JTable 視窗的表格模型;每一個 // 查詢顯示欄位有一個直欄,查詢結果集的每一列有一列。 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]; } }; // 建構含有選用按鈕的查詢結果視窗, // 以顯示所選取列中的記錄(用於 View Record 及 // Modify Record 範例) 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; } /** * 物件的簡易介面,會顯示 Record 資源。 *(用於 ExecuteQuery 範例的延伸規格。) */ static interface Viewer { /** * 顯示 Record 資源 * @param resource 要顯示之記錄的 Record proxy。 * @return TODO */ JFrame view(CqRecord resource); } /** * ExecuteQuery 範例的主程式。 * @param args 不使用。 * @throws Exception 如果提供者無法實例化。 */ 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 Proxy 的 ResourceList。此清單會依查詢的位置排序,並呈現給使用者,供其選擇要執行的單一查詢。
如果要選擇資料庫和選擇查詢,則會使用同樣的通用 Swing 方法,即 JOptionPane.showInputDialog。 此輸入是供選取的 Proxy 陣列,其結果則為選取的 Proxy。 Proxy toString() 方法是用來產生要對使用者顯示的清單。 Proxy 的 toString() 方法會產生 Proxy 位置欄位的影像,亦即 Resource.location().string()。
因為顯示的是 Proxy 的位置,所以我們需要確定那是對使用者友善的 Proxy 位置,也就是包含分段路徑名稱而非資料庫 ID。 伺服器可在其傳回的 Proxy 中自由使用任何形式的位置。 一般來說,如果 Proxy 是用來返回到伺服器的話,則會選取最有處理效率的格式。 最有效率的格式很少是對使用者友善的。 在任何情況下,用戶端都不應該假定要使用的位置形式。 因此,當我們要求資料庫清單及查詢清單時,我們也會要求該清單上每一個項目的 USER_FRIENDLY_LOCATION 內容。 然後,在 setUserFriendlyLocation 方法中,我們會以對使用者友善的版本來修改每一個 Proxy 的位置。
此應用程式會忽略選取的查詢定義動態過濾器(也稱為查詢參數)的可能性,並顯示奇怪的行為,如果選取的查詢具有動態過濾器,此應用程式可能會失敗。 更健全的實作會向伺服器要求查詢的 DYNAMIC_FILTERS 內容,並在執行該查詢之前向使用者取得遺漏的資料。 這留待讀者自行練習。
請注意,當 CqRowData 物件放入陣列中以顯示時,會在每一列呼叫 CqRowData.getValues()。 這是必要的動作,因為在釋放 CqResultSet 疊代子之後無法使用以 Java™ 物件計算列資料值時所需的資訊,而這種情況會在此疊代子到達結尾時自動發生。
本範例未使用 ExecuteQuery.showResults(指名的檢視器)的第二個參數,但下一個範例會使用它,以容許使用者選取一列結果集並顯示相關聯的記錄。