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()); }});
// ユーザーにクエリーのリストを示し、1 つを選択できるようにします。
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 結果セットの単一リソースの詳細表示に使用される
* ビューア インスタンス。NULL にすることができます。その場合、
* 単一リソースを表示するためのオプションは示されません。
*/
static void showResults(String title, final Viewer viewer) {
// JTable ウィンドウのテーブル モデルを定義します。クエリーの表示フィールドごとに
// 1 列、クエリーの結果セットの行ごとに 1 行を定義します。
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]; }
};
// 選択された行の中のレコードを表示するオプション ボタンを指定して、
// クエリー結果ウィンドウを構成します (『レコードの表示』および
// 『レコードの修正』の例で使用)
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;
}
/**
* レコード リソースを表示するオブジェクトのシンプルなインターフェイス。
* (ExecuteQuery の例の拡張で使用。)
*/
static interface Viewer {
/**
* レコード リソースを表示します
* @param resource 表示するレコードのレコード プロキシ。
* @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);
}
}
この例では、前の演習と同様に使用可能なデータベースのリストが作成されます。そして、ログインするデータベースを 1 つ選択できるように、そのリストがユーザーに示されます。
ユーザーがユーザー データベースを選択すると、そのデータベースの ALL_QUERIES プロパティがアプリケーションに読み込まれます。このプロパティの値は CqQuery プロキシの ResourceList です。このリストがクエリーのロケーションでソートされ、実行するクエリーを 1 つ選択するようユーザーに提示されます。
データベースの選択およびクエリーの選択では、同じ汎用 Swing メソッド JOptionPane.showInputDialog が使用されます。 入力は選択肢となるプロキシの配列で、結果は選択されたプロキシです。プロキシ toString() メソッドを使用して、ユーザーに表示されるリストを生成します。プロキシの toString() メソッドはプロキシのロケーション フィールド (すなわち、Resource.location().string()) のイメージを生成します。
プロキシのロケーションが表示されるため、そのプロキシのロケーションが分かりやすいものであること、つまりデータベース ID ではなくセグメント化されたパス名で構成されるようにする必要があります。サーバーは、それが戻すプロキシの中で任意の形式のロケーションを使用でき、通常、サーバーに戻すためにプロキシが使用される場合には、最も効率的に処理される形式を選択します。最も効率的な形式が、同時にわかりやすい形式であることはまれで す。 いずれの場合にも、クライアントは、どの形式のロケーションが使用されるかを決めてかかるべきではありません。したがって、データベース リストとクエリー リストを要求するときに、リスト上の各項目に USER_FRIENDLY_LOCATION プロパティも要求します。 その後、setUserFriendlyLocation メソッドで、それぞれのプロキシのロケーションを分かりやすい形式のものに修正します。
このアプリケーションは、選択されたクエリーが動的フィルタ (クエリー パラメータとも呼ばれます) を定義する可能性を無視しているため、選択されたクエリーに動的フィルタが含まれていると、正常でない動作を示したり、失敗したりします。さらに堅固な実装を行うためには、サーバーからのクエリーに DYNAMIC_FILTERS プロパティを要求し、そのクエリーが実行される前にユーザーから欠落データを取得します。これについては、読者の練習課題として残します。
CqRowData オブジェクトが表示のために配列に入れられると、それぞれの行で CqRowData.getValues() が呼び出されます。これが必要なのは、Java™ オブジェクトとして行のデータ値を計算するために必要な情報が、CqResultSet イテレータが解除された後は使用不可になるためです。この解除は、終わりに到達したときに自動的に行われます。
ExecuteQuery.showResults に対する 2 つ目のパラメータ (viewer という名前です) は、このサンプルでは使用しませんが、次の例ではこれを使用して、ユーザーが結果セットの行を選択して関連するレコードを表示できるようにします。