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