From 4cc84b6399aaded5f095337d6a3394ca5ab443f5 Mon Sep 17 00:00:00 2001 From: Nathanael Jourdane Date: Wed, 17 Feb 2016 17:26:29 +0100 Subject: [PATCH] Add the possibility to send queries to the selected service. --- src/main/java/eu/omp/irap/vespa/epntapclient/EpnTapMainApp.java | 2 +- src/main/java/eu/omp/irap/vespa/epntapclient/controller/EpnTapController.java | 41 ++++++++++++++++++++++++++++++++--------- src/main/java/eu/omp/irap/vespa/epntapclient/utils/Queries.java | 3 +++ src/main/java/eu/omp/irap/vespa/epntapclient/view/EpnTapMainView.java | 51 +++++++++++++++++++++++++++++++++++---------------- src/main/java/eu/omp/irap/vespa/epntapclient/view/RequestView.java | 37 ++++++++++++++++++++++++++++--------- src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableConnection.java | 6 ++++-- src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableController.java | 72 ++++++++++++++++++++++++++++++++++++++---------------------------------- src/main/java/eu/omp/irap/vespa/epntapclient/votable/view/VOTableView.java | 104 +++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------- 8 files changed, 188 insertions(+), 128 deletions(-) diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/EpnTapMainApp.java b/src/main/java/eu/omp/irap/vespa/epntapclient/EpnTapMainApp.java index 6824d23..e26e75b 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/EpnTapMainApp.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/EpnTapMainApp.java @@ -49,7 +49,7 @@ public class EpnTapMainApp { frame.setContentPane(epnTapControl.getView()); frame.setVisible(true); // frame.pack(); - frame.setSize(800, 600); + frame.setSize(1000, 600); frame.setLocationRelativeTo(null); } }); diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/controller/EpnTapController.java b/src/main/java/eu/omp/irap/vespa/epntapclient/controller/EpnTapController.java index 5fb0cf8..0cd9fdd 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/controller/EpnTapController.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/controller/EpnTapController.java @@ -17,6 +17,7 @@ package eu.omp.irap.vespa.epntapclient.controller; import eu.omp.irap.vespa.epntapclient.utils.Const; +import eu.omp.irap.vespa.epntapclient.utils.Log; import eu.omp.irap.vespa.epntapclient.utils.Queries; import eu.omp.irap.vespa.epntapclient.view.EpnTapMainView; import eu.omp.irap.vespa.epntapclient.votable.controller.VOTableController; @@ -29,27 +30,29 @@ public class EpnTapController { /** The view of EPN-TAP application. */ EpnTapMainView view; + /** The controller of the VOTable displaying the list of services. */ + VOTableController servicesController; + /** The controller of the VOTable displaying the query results. */ VOTableController resultsController; - /** The controller of the VOTable displaying the list of services. */ - VOTableController servicesController; + /** The URL of the service selected by the user on the services list panel. */ + String selectedServiceURL; /** * Method constructor */ public EpnTapController() { + // TODO: Get only *EPN* TAP services servicesController = new VOTableController(Const.DEFAULT_REGISTRY_URL, "ADQL", Queries.GET_TAP_SERVICES); - VOTableView serviceView = servicesController.getView(); - - view = new EpnTapMainView(this, serviceView); + resultsController = new VOTableController(); - String[] rColumns = { "result name", "result value" }; - String[][] rValues = { { "r1", "r2" }, { "123", "456" } }; - - view.fillResults(rColumns, rValues); + VOTableView serviceView = servicesController.getView(); + VOTableView resultsView = resultsController.getView(); + view = new EpnTapMainView(this, serviceView, resultsView); + setSelectedService(0); } /** @@ -72,4 +75,24 @@ public class EpnTapController { public VOTableController getServicesController() { return servicesController; } + + /** + * @param row The row selected by the user on the Jtable. + */ + public void setSelectedService(int row) { + String serviceURL = (String) view.getServices().getValueAt(1, row); + if (!serviceURL.equals(selectedServiceURL)) { + selectedServiceURL = serviceURL; + Log.LOGGER.info("Selected service URL: " + selectedServiceURL); + } + } + + /** + * @param query The query to send to the selected service. + * @throws Exception If the Table can not be filled. + */ + public void sendQuery(String query) throws Exception { + Log.LOGGER.info("Sending query: " + query + " on " + selectedServiceURL); + resultsController.fillTable(selectedServiceURL, "ADQL", query); + } } diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/utils/Queries.java b/src/main/java/eu/omp/irap/vespa/epntapclient/utils/Queries.java index dbf50e2..699a6b5 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/utils/Queries.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/utils/Queries.java @@ -49,4 +49,7 @@ public class Queries { /** Minimal query to get TAP all services of the registry, using GloTS. */ public static final String GET_TAP_SERVICES = "SELECT ivoid, accessurl FROM glots.services"; + /** A sample query for tests. */ + public static final String SAMPLE_AMDA_QUERY = "SELECT TOP 5 index, resource_type, time_min, time_max FROM amdadb.epn_core"; + } diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/view/EpnTapMainView.java b/src/main/java/eu/omp/irap/vespa/epntapclient/view/EpnTapMainView.java index c72afcd..c68ea6d 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/view/EpnTapMainView.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/view/EpnTapMainView.java @@ -17,6 +17,12 @@ package eu.omp.irap.vespa.epntapclient.view; import java.awt.BorderLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -41,36 +47,48 @@ public class EpnTapMainView extends JPanel { /** The JPanel where the user put requests. */ private RequestView requestView; + /** The main EPN-TAP main controller */ + private EpnTapController controller; + /** * The constructor of the view. * * @param controller The EPN-TAP controller, allowing the EPN-TAP view to send events. * @param servicesView The JPanel representing the table of services. + * @param resultsView The JPanel representing the table of results. */ - public EpnTapMainView(EpnTapController controller, VOTableView servicesView) { + public EpnTapMainView(EpnTapController controller, VOTableView servicesView, + VOTableView resultsView) { + this.controller = controller; this.servicesView = servicesView; - resultsView = new VOTableView(controller.getResultsController()); + this.resultsView = resultsView; this.requestView = new RequestView(this); buildWindow(); - } - /** - * @param columns The name of each column to fill the Service table. - * @param values A 2D array, where the first dimension represents the rows of the Services - * table. The second one represents each element, in the same order as the `columns`. - */ - public void fillServices(String[] columns, Object[][] values) { - servicesView.buildArray(columns, values); + // TODO: support multi-selection + KeyListener tableKeyListener = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + controller.setSelectedService(servicesView.getTable().getSelectedRow()); + } + }; + MouseListener tableMouseListener = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + controller.setSelectedService(servicesView.getTable().getSelectedRow()); + } + }; + + servicesView.getTable().addKeyListener(tableKeyListener); + servicesView.getTable().addMouseListener(tableMouseListener); } /** - * @param columns The name of each column to fill the Results table. - * @param values A 2D array, where the first dimension represents the rows of the Results table. - * The second one represents each element, in the same order as the `columns`. + * @return The main EPNT-TAP controller. */ - public void fillResults(String[] columns, Object[][] values) { - resultsView.buildArray(columns, values); + public EpnTapController getController() { + return controller; } /** @@ -107,7 +125,8 @@ public class EpnTapMainView extends JPanel { * @param message The message of the error. */ public void displayError(String title, String message) { - JOptionPane.showMessageDialog(this, message, title, JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, message, title, + JOptionPane.ERROR_MESSAGE); } } diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/view/RequestView.java b/src/main/java/eu/omp/irap/vespa/epntapclient/view/RequestView.java index fdcc731..45e5d51 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/view/RequestView.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/view/RequestView.java @@ -17,15 +17,21 @@ package eu.omp.irap.vespa.epntapclient.view; import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; +import eu.omp.irap.vespa.epntapclient.utils.Log; +import eu.omp.irap.vespa.epntapclient.utils.Queries; + /** * @author N. Jourdane */ -public class RequestView extends JPanel { +public class RequestView extends JPanel implements ActionListener { /** The serial version UID (affected with a random number). */ private static final long serialVersionUID = 1262856496809315405L; @@ -33,11 +39,8 @@ public class RequestView extends JPanel { /** The EPN-TAP main view. */ EpnTapMainView mainView; - /** The text area where the user put its requests. */ - private JTextArea queryArea; - - /** The text area where the user put its requests. */ - private JLabel queryTitle; + /** The text area where the user put the query. */ + JTextArea queryArea; /** * Method constructor @@ -46,12 +49,28 @@ public class RequestView extends JPanel { */ public RequestView(EpnTapMainView mainView) { this.mainView = mainView; - queryArea = new JTextArea(""); - queryTitle = new JLabel("Query for the selected service"); - + JLabel queryTitle = new JLabel("Query for the selected service"); + queryArea = new JTextArea(Queries.SAMPLE_AMDA_QUERY); + JButton button = new JButton("Send query"); + button.setName("btnSend"); setLayout(new BorderLayout()); + this.add(queryTitle, BorderLayout.NORTH); this.add(queryArea, BorderLayout.CENTER); + this.add(button, BorderLayout.SOUTH); + + button.addActionListener(this); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (((JButton) e.getSource()).getName() == "btnSend") { + try { + mainView.getController().sendQuery(queryArea.getText()); + } catch (Exception e1) { + Log.LOGGER.severe(e1.getMessage()); + } + } } } diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableConnection.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableConnection.java index 65ab743..71b689d 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableConnection.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableConnection.java @@ -56,13 +56,14 @@ public class VOTableConnection { int responseCode = -1; String uri = targetURL + "/sync"; String parameters = "REQUEST=doQuery&LANG=" + queryLanguage + "&QUERY="; - parameters += URLEncoder.encode(query, Const.CHARACTER_SET); + parameters += URLEncoder.encode(query, Const.CHARACTER_SET).replace("+", "%20") + .replace(".", "%2E").replace("-", "%2D").replace("*", "%2A").replace("_", "%5F"); Log.LOGGER.info("request: " + uri + "?" + parameters); try { responseCode = VOTableConnection.sendGet(uri, parameters, voTablePath); } catch (Exception e1) { - throw new Exception("Can not send the specified query: " + uri + "?" + query, e1); + throw new Exception("Can not send the request: " + uri + "?" + parameters, e1); } if (responseCode != 200) { throw new Exception("Bad response code for the query: " + query); @@ -85,6 +86,7 @@ public class VOTableConnection { URL obj = new URL(url + "?" + urlParameters); int responseCode = -1; + // TODO: Récupérer le message d'erreur de la VOTable (VOTABLE/RESOURCE/INFO) try { HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("GET"); diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableController.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableController.java index cd7cb80..b7b8429 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableController.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableController.java @@ -16,7 +16,6 @@ package eu.omp.irap.vespa.epntapclient.votable.controller; -import eu.omp.irap.vespa.epntapclient.utils.Log; import eu.omp.irap.vespa.epntapclient.votable.model.Table; import eu.omp.irap.vespa.epntapclient.votable.model.VOTABLE; import eu.omp.irap.vespa.epntapclient.votable.view.VOTableView; @@ -32,11 +31,12 @@ public class VOTableController { /** The VOTable model */ VOTABLE voTable; - /** The table column selected by the user. */ - int selectedColumn; - - /** The table row selected by the user. */ - int selectedRow; + /** + * Method constructor + */ + public VOTableController() { + view = new VOTableView(); + } /** * Method constructor @@ -44,13 +44,10 @@ public class VOTableController { * @param voTablePath The path of the VOTable XML file. */ public VOTableController(String voTablePath) { - view = new VOTableView(this); - selectedColumn = -1; - selectedRow = -1; + view = new VOTableView(); try { - voTable = VOTableParser.parseVOTable(voTablePath); - fillView(); + fillTable(voTablePath); } catch (Exception e) { view.displayError("VOTable can not be displayed.\nReason:\n", e.getMessage()); } @@ -64,36 +61,51 @@ public class VOTableController { * @param query The query to ask to the registry. */ public VOTableController(String targetURL, String queryLanguage, String query) { - view = new VOTableView(this); - String voTablePath; + view = new VOTableView(); try { - voTablePath = VOTableConnection.sendQuery(targetURL, queryLanguage, - query); - voTable = VOTableParser.parseVOTable(voTablePath); - fillView(); + fillTable(VOTableConnection.sendQuery(targetURL, queryLanguage, query)); } catch (Exception e) { view.displayError("VOTable can not be displayed.\nReason:\n", e.getMessage()); } } + public void fillTable(String targetURL, String queryLanguage, String query) throws Exception { + fillTable(VOTableConnection.sendQuery(targetURL, queryLanguage, query)); + } + /** - * Fill the view with the VOTable data. - * - * @throws Exception If there are more than 1 resource or table in the VOTable. + * @param voTablePath The path of the VOTable file. + * @throws Exception If VOTable can not be parsed or there is more than one VOTable. */ - private void fillView() throws Exception { + public void fillTable(String voTablePath) throws Exception { + try { + voTable = VOTableParser.parseVOTable(voTablePath); + } catch (Exception e) { + throw new Exception("Can not parse the VOTable.\n" + e.getMessage()); + } + // TODO: Traiter le cas où il y a plus d'une ressource et d'une table. - if (voTable.getRESOURCE().size() != 1) { - throw new Exception("VOTable with more than one resource are not yet supported."); + if (voTable.getRESOURCE().size() > 1) { + view.displayError("Several resources", + "VOTable with more than one resource are not yet supported. See VOTable file for debug:\n" + + voTablePath); } - if (voTable.getRESOURCE().get(0).getLINKAndTABLEOrRESOURCE().size() != 1) { - throw new Exception("VOTable with more than one table are not yet supported."); + // TODO: iterate over all potential errors + if (voTable.getRESOURCE().get(0).getINFO().get(0).getValueAttribute().equals("ERROR")) { + view.displayError("Bad query", "There is an error on the query:\n" + + voTable.getRESOURCE().get(0).getINFO().get(0).getValue()); + } + if (voTable.getRESOURCE().get(0).getLINKAndTABLEOrRESOURCE().size() > 1) { + view.displayError("Several tables", + "VOTable with more than one table are not yet supported. See VOTable file for debug:\n" + + voTablePath); } Table table = (Table) (voTable.getRESOURCE().get(0).getLINKAndTABLEOrRESOURCE().get(0)); + System.out.println(table); VOTableDataParser dataParser = new VOTableDataParser(table); - view.buildArray(dataParser.getColumnsName(), dataParser.getDataArray()); + view.fillTable(dataParser.getColumnsName(), dataParser.getDataArray()); } /** @@ -102,12 +114,4 @@ public class VOTableController { public VOTableView getView() { return view; } - - /** - * @param selectedColumn The table column selected by the user. - * @param selectedRow The table row selected by the user. - */ - public void updateSelection(int selectedColumn, int selectedRow) { - Log.LOGGER.info("Selection updated: [" + selectedColumn + " ; " + selectedRow + "]"); - } } diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/view/VOTableView.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/view/VOTableView.java index 6d82db4..01cb338 100644 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/view/VOTableView.java +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/view/VOTableView.java @@ -17,12 +17,6 @@ package eu.omp.irap.vespa.epntapclient.votable.view; import java.awt.BorderLayout; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import java.util.List; import javax.swing.JOptionPane; @@ -30,73 +24,41 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ScrollPaneConstants; - -import eu.omp.irap.vespa.epntapclient.votable.controller.VOTableController; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableModel; /** * The main class of the View of the application. * * @author N. Jourdane */ -public class VOTableView extends JPanel { +public class VOTableView extends JPanel implements TableModelListener { /** The serial version UID (affected with a random number). */ private static final long serialVersionUID = -1233290271099283814L; - /** The VOTable controller, allowing the view to send events. */ - private VOTableController controller; - /** The JTable component where the data are displayed. */ private JTable table; - /** - * Method constructor - * - * @param controller The VOTable controller, allowing the view to send events. - */ - public VOTableView(VOTableController controller) { - this.controller = controller; - } + /** The DataModel representing the VOTable data in the JTable element. */ + DefaultTableModel tableData; /** - * Build and fill the GUI. - * - * @param keys The name of each column of the VOTable data. - * @param values A list of arrays, representing the rows of the VOTable data. In each row, - * elements are in the same order as `keys`. - */ - public void buildArray(String[] keys, List values) { - Object valuesArray[][] = values.toArray(new Object[values.size()][]); - buildArray(keys, valuesArray); - } - - /** - * Build and fill the GUI. - * - * @param keys The name of each column of the VOTable data. - * @param values A 2D array, where the first dimension represents the rows of the VOTable data. - * The second one represents each element, in the same order as `keys`. + * Method constructor */ - public void buildArray(String[] keys, Object[][] values) { - table = new JTable(values, keys); + public VOTableView() { + tableData = new DefaultTableModel() { + /** The serial version UID (affected with a random number). */ + private static final long serialVersionUID = 8195913508549662555L; - // TODO: support multi-selection - KeyListener tableKeyListener = new KeyAdapter() { @Override - public void keyPressed(KeyEvent e) { - updateSelection(); - } - }; - MouseListener tableMouseListener = new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - updateSelection(); + public boolean isCellEditable(int row, int column) { + return false; } }; - table.addKeyListener(tableKeyListener); - table.addMouseListener(tableMouseListener); - + table = new JTable(tableData); JScrollPane scrollPane = new JScrollPane(table); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); @@ -106,20 +68,48 @@ public class VOTableView extends JPanel { } /** - * This method is called on keyPressed and mouseClicked events on the JTable. + * Fill the JTable. + * + * @param columns the column names + * @param data The VoTable data displayed on the JTable + */ + public void fillTable(String[] columns, List data) { + Object values[][] = data.toArray(new Object[data.size()][]); + tableData.setDataVector(values, columns); + table.setRowSelectionInterval(0, 0); + } + + /** + * @return The JTable element. */ - void updateSelection() { - controller.updateSelection(table.getSelectedColumn(), table.getSelectedRow()); + public JTable getTable() { + return table; + } + + /** + * @param column The column index of the data to get. + * @param row The row index of the data to get. + * @return The element, can be a String, a integer or something else, according to the voTable + * content. + */ + public Object getValueAt(int column, int row) { + return tableData.getValueAt(row, column); } /** * Display an error. * - * @param title The title of the error. - * @param message The message of the error. + * @param title The title of the window. + * @param message The error message to display. */ public void displayError(String title, String message) { JOptionPane.showMessageDialog(this, message, title, JOptionPane.ERROR_MESSAGE); } + @Override + public void tableChanged(TableModelEvent e) { + if (e.getType() != TableModelEvent.UPDATE) + return; + } + } -- libgit2 0.21.2