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(指名的檢視器)的第二個參數,但下一個範例會使用它,以容許使用者選取一列結果集並顯示相關聯的記錄。