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))); // Convertit la liste en un tableau trié à utiliser dans la boîte de dialogue de sélection 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()); }}); // Présente la liste de requêtes à l'utilisateur et lui permet de sélectionner une requête 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); // Si la requête s'est correctement exécutée, sauvegardez les données et préparez-les pour l'affichage if (results.hasNext()) { // Informations de colonne accessibles depuis l'afficheur g_columns = results.getColumnLabels(); g_cell = new CqRowData[(int)results.getRowCount()]; for (CqRowData row: results) (g_cell[(int)row.getRowNumber()-1] = row).getValues(); // Affiche les données de résultats de la requête showResults(query.location().string(), viewer); } } /** L'ensemble de résultats rendu accessible aux composants de l'interface graphique pour affichage */ static CqRowData[] g_cell; /** Les en-têtes de colonnes rendus accessibles aux composants de l'interface graphique pour affichage */ static String[] g_columns; /** * Affiche l'ensemble de résultats (dans g_cell) dans une table. * * @param title : chaîne de titre de l'ensemble de résultats pour la fenêtre d'ensemble de résultats * @param viewer : une instance d'afficheur à utiliser pour l'affichage détaillé d'une * seule ressource de l'ensemble de résultats. Elle peut être nulle, auquel cas * l'option d'affichage d'une seule ressource n'est pas présentée. */ static void showResults(String title, final Viewer viewer) { // Définit le modèle de table pour la fenêtre JTable ; une colonne pour chaque // zone d'affichage de requête et une ligne pour chaque ligne de l'ensemble de résultats de requête. 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]; } }; // Construit la fenêtre de résultat de la requête à l'aide d'un bouton d'option pour // afficher l'enregistrement d'une ligne sélectionnée (utilisé dans les exemples d'Enregistrement de vue // et d'Enregistrement de changement) 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; } /** * Une interface simple pour un objet qui affichera une Ressource d'enregistrement * (utilisé par les extensions pour l'exemple ExecuteQuery). */ static interface Viewer { /** * Affiche une Ressource d'enregistrement * @param resource : proxy d'enregistrement pour l'enregistrement à afficher. * @return TODO */ JFrame view(CqRecord resource); } /** * Le programme principal pour l'exemple ExecuteQuery. * @param args : non utilisé. * @throws : exception si un fournisseur ne peut pas être instancié. */ 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); } }
Dans cet exemple, la liste des bases de données disponibles est créée comme dans la leçon précédente. Et la liste est présentée à l'utilisateur pour qu'il sélectionne une seule base de données à laquelle se connecter.
Une fois que l'utilisateur a sélectionné une base de données utilisateur, la propriété ALL_QUERIES de cette base de données est lue dans l'application. La valeur de cette propriété est une ResourceList de proxys CqQuery. Cette liste est triée par rapport à l'emplacement de la requête et est présentée à l'utilisateur afin qu'il sélectionne une seule requête à exécuter.
Pour la sélection de la base de données et la sélection de la requête, la même méthode Swing à but général, JOptionPane.showInputDialog, est utilisée. L'entrée est le tableau de proxys dans lequel effectuer la sélection et le résultat est le proxy sélectionné. La méthode proxy toString() est utilisée pour générer la liste affichée à l'utilisateur. La méthode toString() d'un proxy génère une image de la zone d'emplacement du proxy, c'est-à-dire Resource.location().string().
L'emplacement du proxy étant affiché, nous devons nous assurer qu'il est convivial, c'est-à-dire composé de noms de chemin segmentés et non d'ID de bases de données. Les serveurs sont libres d'utiliser n'importe quel format d'emplacement dans les proxys qu'ils renvoient et, en général, sélectionneront le format qui est le plus efficacement traité si le proxy est utilisé pour revenir au serveur. Le format le plus efficace est rarement convivial. Dans tous les cas, un client ne doit pas supposer le format d'emplacement utilisé. Ainsi, lorsque nous demandons la liste de bases de données et la liste de requêtes, nous demandons également la propriété USER_FRIENDLY_LOCATION de chaque élément de la liste. Puis, dans la méthode setUserFriendlyLocation, nous modifions l'emplacement de chaque proxy avec sa version conviviale.
Cette application ignore la possibilité que la requête sélectionnée définisse des filtres dynamiques (également appelés paramètres de la requête) et présentera un comportement étrange ou peut-être un échec si la requête sélectionnée comporte des filtres dynamiques. Une implémentation plus robuste demanderait la propriété DYNAMIC_FILTERS de la requête auprès du serveur et obtiendrait les données manquantes de l'utilisateur avant d'exécuter la requête. Le lecteur peut s'y exercer.
Notez que CqRowData.getValues() est appelé sur chaque ligne au fur et à mesure que l'objet CqRowData est placé dans le tableau pour affichage. Cela est nécessaire car les informations requises pour calculer les valeurs de données de ligne en tant qu'objets Java ne sont pas disponibles une fois que l'itérateur CqResultSet est libéré, ce qui se produit automatiquement lorsqu'il atteint la fin.
Le second paramètre de ExecuteQuery.showResults (afficheur désigné) n'est pas utilisé dans cet exemple mais le sera dans le suivant pour permettre à l'utilisateur de sélectionner une ligne de l'ensemble de résultats et d'afficher l'enregistrement associé.