From: Mateusz Warowny Date: Wed, 8 Jul 2020 12:44:08 +0000 (+0100) Subject: Merge branch 'feature/JAL-3515-slivka-preferences' into alpha/JAL-3066_Jalview_212_sl... X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=9f503489b06e09a6a7aec83048301938e3710863;hp=d02166c8801f0005ac9c1fbffdf0c26c7ca912aa;p=jalview.git Merge branch 'feature/JAL-3515-slivka-preferences' into alpha/JAL-3066_Jalview_212_slivka-integration --- diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index e66b8d1..9647e0f 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -102,6 +102,7 @@ import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; +import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; @@ -4414,9 +4415,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } // TODO: move into separate menu builder class. boolean new_sspred = false; + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer(); + WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); if (jws2servs != null) { if (jws2servs.hasServices()) @@ -4443,30 +4445,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } } - build_urlServiceMenu(me.webService); - - - // TODO Mateusz - follow pattern for adding web service - // JMenuItems for slivka-based services - SlivkaWSDiscoverer slivkaDiscoverer = SlivkaWSDiscoverer.getInstance(); - if (slivkaDiscoverer.hasServices()) + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - slivkaDiscoverer.attachWSMenuEntry(webService, me); - } else { - if (slivkaDiscoverer.isRunning()) + WSDiscovererI discoverer = SlivkaWSDiscoverer + .getInstance(); + if (discoverer != null) { + if (discoverer.hasServices()) + { + discoverer.attachWSMenuEntry(webService, me); + } + if (discoverer.isRunning()) { JMenuItem tm = new JMenuItem( "Still discovering Slivka Services"); tm.setEnabled(false); webService.add(tm); } - } } - + build_urlServiceMenu(me.webService); build_fetchdbmenu(webService); for (JMenu item : wsmenu) { diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 84e6aed..2402aef 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -45,6 +45,7 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.UrlConstants; import jalview.viewmodel.AlignmentViewport; +import jalview.ws.WSDiscovererI; import jalview.ws.params.ParamManager; import jalview.ws.utils.UrlDownloadClient; @@ -2534,7 +2535,7 @@ public class Desktop extends jalview.jbgui.GDesktop public void startServiceDiscovery(boolean blocking) { boolean alive = true; - Thread t0 = null, t1 = null, t2 = null; + Thread t0 = null, t1 = null, t2 = null, t3 = null; // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release if (true) { @@ -2552,14 +2553,14 @@ public class Desktop extends jalview.jbgui.GDesktop if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() - .startDiscoverer(changeSupport); + t2 = startServiceDiscovery( + jalview.ws.jws2.Jws2Discoverer.getDiscoverer(), false); } - Thread t3 = null; + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { // start slivka discovery - t3 = new Thread(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance()); - t3.start(); + t3 = startServiceDiscovery( + jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance(), false); } if (blocking) { @@ -2571,13 +2572,31 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (Exception e) { } + // FIXME: Condition should check the discoverer's isRunning rather than + // threads alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive()) - || (t3 != null && t3.isAlive()) - || (t0 != null && t0.isAlive()); + || (t3 != null && t3.isAlive()) || (t0 != null && t0.isAlive()); } } } + public Thread startServiceDiscovery(WSDiscovererI discoverer, + boolean blocking) + { + Thread thread = discoverer.startDiscoverer(changeSupport); + if (blocking) + { + try + { + thread.join(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + return thread; + } + /** * called to check if the service discovery process completed successfully. * @@ -2587,8 +2606,9 @@ public class Desktop extends jalview.jbgui.GDesktop { if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) { - final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() - .getErrorMessages(); + final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer + .getDiscoverer(); + final String ermsg = discoverer.getErrorMessages(); if (ermsg != null) { if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true)) diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index a0a7511..c921331 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -192,6 +192,8 @@ public class Preferences extends GPreferences private WsPreferences wsPrefs; + private SlivkaPreferences slivkaPrefs; + private OptionsParam promptEachTimeOpt = new OptionsParam( MessageManager.getString("label.prompt_each_time"), "Prompt each time"); @@ -212,6 +214,8 @@ public class Preferences extends GPreferences frame.setContentPane(this); wsPrefs = new WsPreferences(); wsTab.add(wsPrefs, BorderLayout.CENTER); + slivkaTab.add(slivkaPrefs = new SlivkaPreferences(), + BorderLayout.CENTER); int width = 500, height = 450; new jalview.util.Platform(); if (Platform.isAMac()) @@ -481,7 +485,7 @@ public class Preferences extends GPreferences doReset.addActionListener(onReset); // filter to display only custom urls - final RowFilter customUrlFilter = new RowFilter() + final RowFilter customUrlFilter = new RowFilter<>() { @Override public boolean include( diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java new file mode 100644 index 0000000..f4f6a9a --- /dev/null +++ b/src/jalview/gui/SlivkaPreferences.java @@ -0,0 +1,360 @@ +package jalview.gui; + +import jalview.bin.Cache; +import jalview.util.MessageManager; +import jalview.ws.WSDiscovererI; +import jalview.ws.slivkaws.SlivkaWSDiscoverer; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +@SuppressWarnings("serial") +public class SlivkaPreferences extends JPanel +{ + { + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + setPreferredSize(new Dimension(500, 450)); + } + + WSDiscovererI discoverer; + + private final ArrayList urls = new ArrayList<>(); + + private final ArrayList statuses = new ArrayList<>(); + + private final AbstractTableModel urlTableModel = new AbstractTableModel() + { + final String[] columnNames = { "Service URL", "Status" }; + + @Override + public String getColumnName(int col) + { + return columnNames[col]; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) + { + switch (columnIndex) + { + case 0: + return urls.get(rowIndex); + case 1: + return statuses.get(rowIndex); + default: + throw new NoSuchElementException(); + } + } + + @Override + public int getRowCount() + { + return urls.size(); + } + + @Override + public int getColumnCount() + { + return 2; + } + }; + + private class WSStatusCellRenderer extends DefaultTableCellRenderer + { + @Override + public Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, int row, + int column) + { + setHorizontalAlignment(CENTER); + super.getTableCellRendererComponent(table, "\u25CF", isSelected, + hasFocus, row, column); + switch ((Integer) value) + { + case WSDiscovererI.STATUS_NO_SERVICES: + setForeground(Color.ORANGE); + break; + case WSDiscovererI.STATUS_OK: + setForeground(Color.GREEN); + break; + case WSDiscovererI.STATUS_INVALID: + setForeground(Color.RED); + break; + case WSDiscovererI.STATUS_UNKNOWN: + default: + setForeground(Color.LIGHT_GRAY); + } + return this; + } + } + + private JTable urlListTable = new JTable(urlTableModel); + { + urlListTable.getColumnModel().getColumn(1).setMaxWidth(60); + urlListTable.getColumnModel().getColumn(1) + .setCellRenderer(new WSStatusCellRenderer()); + } + + // URL control panel buttons + JButton newWsUrl = new JButton( + MessageManager.getString("label.new_service_url")); + + JButton editWsUrl = new JButton( + MessageManager.getString("label.edit_service_url")); + + JButton deleteWsUrl = new JButton( + MessageManager.getString("label.delete_service_url")); + + JButton moveUrlUp = new JButton( + MessageManager.getString("action.move_up")); + + JButton moveUrlDown = new JButton( + MessageManager.getString("action.move_down")); + + private String showEditUrlDialog(String oldUrl) + { + String input = (String) JvOptionPane + .showInternalInputDialog( + this, + MessageManager.getString("label.url:"), + UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()), + JOptionPane.QUESTION_MESSAGE, + null, + null, + oldUrl); + if (input == null) + { + return null; + } + try + { + new URL(input); + } catch (MalformedURLException ex) + { + JvOptionPane.showInternalMessageDialog(this, + MessageManager.getString("label.invalid_url"), + UIManager.getString("OptionPane.messageDialogTitle", + MessageManager.getLocale()), + JOptionPane.WARNING_MESSAGE); + return null; + } + return input; + } + + // Button Action Listeners + private ActionListener newUrlAction = (ActionEvent e) -> { + final String input = showEditUrlDialog(""); + if (input != null) + { + urls.add(input); + statuses.add(discoverer.getServerStatusFor(input)); + urlTableModel.fireTableRowsInserted(urls.size(), urls.size()); + discoverer.setServiceUrls(urls); + } + }; + + private ActionListener editUrlAction = (ActionEvent e) -> { + final int i = urlListTable.getSelectedRow(); + if (i >= 0) + { + final String input = showEditUrlDialog(urls.get(i)); + if (input != null) + { + urls.set(i, input); + statuses.set(i, discoverer.getServerStatusFor(input)); + urlTableModel.fireTableRowsUpdated(i, i); + discoverer.setServiceUrls(urls); + } + } + }; + + private ActionListener deleteUrlAction = (ActionEvent e) -> { + final int i = urlListTable.getSelectedRow(); + if (i >= 0) + { + urls.remove(i); + statuses.remove(i); + urlTableModel.fireTableRowsDeleted(i, i); + discoverer.setServiceUrls(urls); + } + }; + + private ActionListener moveUrlUpAction = (ActionEvent e) -> { + final int i = urlListTable.getSelectedRow(); + if (i > 0) + { + moveTableRow(i, i - 1); + discoverer.setServiceUrls(urls); + } + }; + + private ActionListener moveUrlDownAction = (ActionEvent e) -> { + final int i = urlListTable.getSelectedRow(); + if (i >= 0 && i < urls.size() - 1) + { + moveTableRow(i, i + 1); + discoverer.setServiceUrls(urls); + } + }; + + private MouseListener tableClickListener = new MouseAdapter() + { + final ActionEvent actionEvent = new ActionEvent(urlListTable, + ActionEvent.ACTION_PERFORMED, "edit"); + + @Override + public void mouseClicked(MouseEvent e) + { + if (e.getClickCount() > 1) + { + editUrlAction.actionPerformed(actionEvent); + } + } + }; + + // Setting up URL list Pane + { + Font font = new Font("Verdana", Font.PLAIN, 10); + JPanel urlPaneContainer = new JPanel(new BorderLayout(5, 5)); + urlPaneContainer.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), + "Slivka Web Services"), + BorderFactory.createEmptyBorder(10, 5, 5, 5))); + + newWsUrl.setFont(font); + editWsUrl.setFont(font); + deleteWsUrl.setFont(font); + moveUrlUp.setFont(font); + moveUrlDown.setFont(font); + JPanel editContainer = new JPanel(); + editContainer.add(newWsUrl); + editContainer.add(editWsUrl); + editContainer.add(deleteWsUrl); + urlPaneContainer.add(editContainer, BorderLayout.PAGE_END); + + JPanel moveContainer = new JPanel(); + moveContainer + .setLayout(new BoxLayout(moveContainer, BoxLayout.PAGE_AXIS)); + moveContainer.add(moveUrlUp); + moveContainer.add(Box.createRigidArea(new Dimension(0, 5))); + moveContainer.add(moveUrlDown); + urlPaneContainer.add(moveContainer, BorderLayout.LINE_START); + + urlPaneContainer.add(new JScrollPane(urlListTable), + BorderLayout.CENTER); + this.add(urlPaneContainer); + + // Connecting action listeners + urlListTable.addMouseListener(tableClickListener); + newWsUrl.addActionListener(newUrlAction); + editWsUrl.addActionListener(editUrlAction); + deleteWsUrl.addActionListener(deleteUrlAction); + moveUrlUp.addActionListener(moveUrlUpAction); + moveUrlDown.addActionListener(moveUrlDownAction); + } + + private void moveTableRow(int fromIndex, int toIndex) + { + String url = urls.get(fromIndex); + int status = statuses.get(fromIndex); + urls.set(fromIndex, urls.get(toIndex)); + statuses.set(fromIndex, statuses.get(toIndex)); + urls.set(toIndex, url); + statuses.set(toIndex, status); + if (urlListTable.getSelectedRow() == fromIndex) + { + urlListTable.setRowSelectionInterval(toIndex, toIndex); + } + int firstRow = Math.min(toIndex, fromIndex); + int lastRow = Math.max(fromIndex, toIndex); + urlTableModel.fireTableRowsUpdated(firstRow, lastRow); + } + + // Discoverer reloading buttons + JButton refreshServices = new JButton( + MessageManager.getString("action.refresh_services")); + + JButton resetServices = new JButton( + MessageManager.getString("action.reset_services")); + + JProgressBar progressBar = new JProgressBar(); + + // Discoverer buttons action listeners + private ActionListener refreshServicesAction = (ActionEvent e) -> { + new Thread(() -> { + progressBar.setVisible(true); + Cache.log.info("Requesting service reload"); + Desktop.instance.startServiceDiscovery(discoverer, true); + Cache.log.info("Reloading done"); + progressBar.setVisible(false); + }).start(); + }; + + private ActionListener resetServicesAction = (ActionEvent e) -> { + discoverer.setServiceUrls(null); + urls.clear(); + statuses.clear(); + urls.addAll(discoverer.getServiceUrls()); + for (String url : urls) + { + statuses.add(discoverer.getServerStatusFor(url)); + } + urlTableModel.fireTableDataChanged(); + }; + + { + Font font = new Font("Verdana", Font.PLAIN, 11); + refreshServices.setFont(font); + resetServices.setFont(font); + JPanel container = new JPanel(); + container.add(refreshServices); + container.add(resetServices); + this.add(container); + + // Connecting action listeners + refreshServices.addActionListener(refreshServicesAction); + resetServices.addActionListener(resetServicesAction); + } + + { + progressBar.setVisible(false); + progressBar.setIndeterminate(true); + add(progressBar); + } + + SlivkaPreferences() + { + // Initial URLs loading + discoverer = SlivkaWSDiscoverer.getInstance(); + urls.addAll(discoverer.getServiceUrls()); + for (String url : urls) + { + statuses.add(discoverer.getServerStatusFor(url)); + } + } +} diff --git a/src/jalview/gui/WsPreferences.java b/src/jalview/gui/WsPreferences.java index 5186a26..51b40dd 100644 --- a/src/jalview/gui/WsPreferences.java +++ b/src/jalview/gui/WsPreferences.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.bin.Cache; import jalview.jbgui.GWsPreferences; import jalview.util.MessageManager; +import jalview.ws.WSDiscovererI; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.rest.RestServiceDescription; @@ -33,11 +34,11 @@ import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; +import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; @@ -156,21 +157,22 @@ public class WsPreferences extends GWsPreferences String t = new String(""); switch (((Integer) status).intValue()) { - case 1: + case WSDiscovererI.STATUS_OK: // cb.setSelected(true); // cb.setBackground( c = Color.green; break; - case 0: + case WSDiscovererI.STATUS_NO_SERVICES: // cb.setSelected(true); // cb.setBackground( c = Color.lightGray; break; - case -1: + case WSDiscovererI.STATUS_INVALID: // cb.setSelected(false); // cb.setBackground( c = Color.red; break; + case WSDiscovererI.STATUS_UNKNOWN: default: // cb.setSelected(false); // cb.setBackground( @@ -485,7 +487,7 @@ public class WsPreferences extends GWsPreferences if (validate == JvOptionPane.OK_OPTION) { - if (Jws2Discoverer.testServiceUrl(foo)) + if (Jws2Discoverer.getDiscoverer().testServiceUrl(foo)) { return foo.toString(); } diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index ca11541..34a7c75 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -314,6 +314,8 @@ public class GPreferences extends JPanel */ protected JPanel wsTab = new JPanel(); + protected JPanel slivkaTab = new JPanel(); + /* * Backups tab components * a lot of these are member variables instead of local variables only so that they @@ -421,6 +423,8 @@ public class GPreferences extends JPanel */ wsTab.setLayout(new BorderLayout()); tabbedPane.add(wsTab, MessageManager.getString("label.web_services")); + slivkaTab.setLayout(new BorderLayout()); + tabbedPane.add(slivkaTab, "Slivka Services"); /* * Handler to validate a tab before leaving it - currently only for diff --git a/src/jalview/ws/WSDiscovererI.java b/src/jalview/ws/WSDiscovererI.java new file mode 100644 index 0000000..e5b94f0 --- /dev/null +++ b/src/jalview/ws/WSDiscovererI.java @@ -0,0 +1,34 @@ +package jalview.ws; + +import jalview.ws.api.ServiceWithParameters; + +import java.beans.PropertyChangeListener; +import java.net.URL; +import java.util.List; + +public interface WSDiscovererI extends WSMenuEntryProviderI +{ + public static final int STATUS_OK = 1; + public static final int STATUS_NO_SERVICES = 0; + public static final int STATUS_INVALID = -1; + public static final int STATUS_UNKNOWN = -2; + + public void setServiceUrls(List wsUrls); + + public List getServiceUrls(); + + public List getServices(); + + public boolean testServiceUrl(URL url); + + public int getServerStatusFor(String url); + + // TODO: should not return Thread but something generic providing isRunning method + public Thread startDiscoverer(PropertyChangeListener changeListener); + + public String getErrorMessages(); + + public boolean hasServices(); + + public boolean isRunning(); +} diff --git a/src/jalview/ws/jws2/Jws2Discoverer.java b/src/jalview/ws/jws2/Jws2Discoverer.java index d11174e..197d0ee 100644 --- a/src/jalview/ws/jws2/Jws2Discoverer.java +++ b/src/jalview/ws/jws2/Jws2Discoverer.java @@ -23,7 +23,7 @@ package jalview.ws.jws2; import jalview.bin.Cache; import jalview.gui.AlignFrame; import jalview.util.MessageManager; -import jalview.ws.WSMenuEntryProviderI; +import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws2.jabaws2.Jws2Instance; import jalview.ws.params.ParamDatastoreI; @@ -51,7 +51,7 @@ import compbio.ws.client.Services; * @author JimP * */ -public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI +public class Jws2Discoverer implements WSDiscovererI, Runnable { public static final String COMPBIO_JABAWS = "http://www.compbio.dundee.ac.uk/jabaws"; @@ -415,16 +415,19 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return discoverer; } + @Override public boolean hasServices() { return !running && services != null && services.size() > 0; } + @Override public boolean isRunning() { return running; } + @Override public void setServiceUrls(List wsUrls) { if (wsUrls != null && !wsUrls.isEmpty()) @@ -451,6 +454,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * * @return */ + @Override public List getServiceUrls() { if (testUrls != null) @@ -504,6 +508,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return urls; } + @Override public Vector getServices() { return (services == null) ? new Vector<>() @@ -516,7 +521,8 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @param foo * @return */ - public static boolean testServiceUrl(URL foo) + @Override + public boolean testServiceUrl(URL foo) { try { @@ -564,6 +570,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @param changeSupport2 * @return new thread */ + @Override public Thread startDiscoverer(PropertyChangeListener changeSupport2) { /* if (restart()) @@ -645,6 +652,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @return a human readable report of any problems with the service URLs used * for discovery */ + @Override public String getErrorMessages() { if (!isRunning() && !isAborted()) @@ -693,21 +701,22 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return null; } + @Override public int getServerStatusFor(String url) { if (validServiceUrls != null && validServiceUrls.contains(url)) { - return 1; + return STATUS_OK; } if (urlsWithoutServices != null && urlsWithoutServices.contains(url)) { - return 0; + return STATUS_NO_SERVICES; } if (invalidServiceUrls != null && invalidServiceUrls.contains(url)) { - return -1; + return STATUS_INVALID; } - return -2; + return STATUS_UNKNOWN; } /** diff --git a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java index 2b4a958..925cd55 100644 --- a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java +++ b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java @@ -1,14 +1,17 @@ package jalview.ws.slivkaws; +import jalview.bin.Cache; import jalview.gui.AlignFrame; -import jalview.ws.WSMenuEntryProviderI; +import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws2.PreferredServiceRegistry; +import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.IOError; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -17,21 +20,18 @@ import javax.swing.JMenu; import uk.ac.dundee.compbio.slivkaclient.SlivkaClient; import uk.ac.dundee.compbio.slivkaclient.SlivkaService; -public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI +public class SlivkaWSDiscoverer implements WSDiscovererI { + private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS"; + + private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka"; + private static SlivkaWSDiscoverer instance = null; - private SlivkaClient slivkaClient; + private List services = List.of(); private SlivkaWSDiscoverer() { - try - { - slivkaClient = new SlivkaClient("https://www.compbio.dundee.ac.uk/slivka"); - } catch (URISyntaxException e) - { - throw new RuntimeException(e); - } } public static SlivkaWSDiscoverer getInstance() @@ -43,111 +43,214 @@ public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI return instance; } - /** - * TODO: tests needed for logic for determining type of each discovered - * service. Then reimplement this routine ! - * - * @return (MSA instances, one AAUI type instance, and the remaining all - * sequence analysis instances taking 1 sequence only) - */ - List getServiceInstances() + private PropertyChangeSupport changeSupport = new PropertyChangeSupport( + this); + + @Override + public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame) + { + JMenu slivkaMenu = new JMenu("Slivka"); + wsmenu.add(slivkaMenu); + + JMenu alignmentMenu = new JMenu("Sequence Alignment"); + slivkaMenu.add(alignmentMenu); + JMenu disorderMenu = new JMenu("Protein sequence analysis"); + slivkaMenu.add(disorderMenu); + JMenu conservationMenu = new JMenu("Conservation"); + slivkaMenu.add(conservationMenu); + PreferredServiceRegistry.getRegistry().populateWSMenuEntry(services, + changeSupport, slivkaMenu, alignFrame, null); + + } + + volatile boolean ready = false; + + volatile Thread discovererThread = null; + + private class DiscovererThread extends Thread { - List instances = new ArrayList<>(); - for (SlivkaService service : services) + private Thread oldThread; + + DiscovererThread(Thread oldThread) + { + super(); + this.oldThread = oldThread; + } + + @Override + public void run() { - ServiceWithParameters newinstance = null; - for (String classifier : service.classifiers) + if (oldThread != null) { - if (classifier.contains("Multiple sequence alignment")) + oldThread.interrupt(); + try { - // MSA services always overwrite - newinstance = new SlivkaMsaServiceInstance(slivkaClient, service); + oldThread.join(); + } catch (InterruptedException e) + { + return; + } finally + { + oldThread = null; } - if (classifier.contains("Protein sequence analysis")) + } + ready = false; + reloadServices(); + ready = !isInterrupted(); + } + } + + Thread discoverer = null; + + @Override + public Thread startDiscoverer(PropertyChangeListener changeListener) + { + changeSupport.addPropertyChangeListener(changeListener); + ready = false; + (discovererThread = new DiscovererThread(discovererThread)).start(); + return discovererThread; + } + + private void reloadServices() + { + Cache.log.info("Reloading Slivka services"); + changeSupport.firePropertyChange("services", services, List.of()); + ArrayList instances = new ArrayList<>(); + + for (String url : getServiceUrls()) + { + Cache.log.info(url); + SlivkaClient client; + try + { + client = new SlivkaClient(url); + } catch (URISyntaxException e) + { + e.printStackTrace(); + continue; + } + try + { + for (SlivkaService service : client.getServices()) { - if (newinstance == null) + SlivkaWSInstance newinstance = null; + for (String classifier : service.classifiers) + { + if (classifier.contains("Multiple sequence alignment")) { - newinstance = (new SlivkaAnnotationServiceInstance( - slivkaClient, - - service, false)); + newinstance = new SlivkaMsaServiceInstance(client, service); } - } - - if (classifier + if (classifier.contains("Protein sequence analysis") + && newinstance == null) + { + newinstance = new SlivkaAnnotationServiceInstance(client, + service, false); + } + if (classifier .contains("Sequence alignment analysis (conservation)")) - { - // always overwrite other instances - newinstance = new SlivkaAnnotationServiceInstance(slivkaClient, + { + newinstance = new SlivkaAnnotationServiceInstance(client, service, true); + } + } + if (newinstance != null) + { + instances.add(newinstance); + } } - } - if (newinstance != null) + } catch (IOException e) { - instances.add(newinstance); + continue; } } - return instances; - } - private PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); + services = instances; + changeSupport.firePropertyChange("services", List.of(), services); + + Cache.log.info("Slivka services reloading finished"); + } @Override - public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame) + public List getServices() { - JMenu slivkaMenu = new JMenu("Slivka"); - wsmenu.add(slivkaMenu); - - JMenu alignmentMenu = new JMenu("Sequence Alignment"); - slivkaMenu.add(alignmentMenu); - JMenu disorderMenu = new JMenu("Protein sequence analysis"); - slivkaMenu.add(disorderMenu); - JMenu conservationMenu = new JMenu("Conservation"); - slivkaMenu.add(conservationMenu); - PreferredServiceRegistry.getRegistry().populateWSMenuEntry( - getServiceInstances(), - changeSupport, slivkaMenu, alignFrame, null); - + return services; } - Listservices=null; + @Override + public boolean hasServices() + { + return ready == true && services.size() > 0; + } - volatile boolean started = false, finished = false; + @Override + public boolean isRunning() + { + return discovererThread == null || discovererThread.isAlive() + || discovererThread.getState() == Thread.State.NEW; + } - Thread discoverer = null; @Override - public void run() + public void setServiceUrls(List wsUrls) { - discoverer = Thread.currentThread(); - started = true; - try + if (wsUrls != null && !wsUrls.isEmpty()) { - services = slivkaClient.getServices(); - } catch (IOException e) + Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls)); + } + else { - throw new IOError(e); + Cache.removeProperty(SLIVKA_HOST_URLS); } - finished = true; } - public static List getServices() + @Override + public List getServiceUrls() { - SlivkaWSDiscoverer us = getInstance(); - if (us.services == null) + String surls = Cache.getDefault(SLIVKA_HOST_URLS, COMPBIO_SLIVKA); + String[] urls = surls.split(","); + ArrayList valid = new ArrayList<>(urls.length); + for (String url : urls) { - us.run(); + try + { + new URL(url); + valid.add(url); + } catch (MalformedURLException e) + { + Cache.log.warn("Problem whilst trying to make a URL from '" + + ((url != null) ? url : "") + "'"); + Cache.log.warn( + "This was probably due to a malformed comma separated list" + + " in the " + SLIVKA_HOST_URLS + + " entry of $(HOME)/.jalview_properties)"); + Cache.log.debug("Exception was ", e); + } } - return us.getServiceInstances(); + return valid; } - public boolean hasServices() + @Override + public boolean testServiceUrl(URL url) { - return finished == true && services != null && services.size() > 0; + return getServerStatusFor(url.toString()) == STATUS_OK; } - public boolean isRunning() + @Override + public int getServerStatusFor(String url) + { + try + { + List services = new SlivkaClient(url).getServices(); + return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK; + } catch (IOException | URISyntaxException e) + { + return STATUS_INVALID; + } + } + + @Override + public String getErrorMessages() { - return discoverer != null && discoverer.isAlive(); + // TODO Auto-generated method stub + return ""; } } diff --git a/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java b/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java index 2a6c3d0..5428acd 100644 --- a/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java +++ b/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java @@ -89,7 +89,8 @@ public class AAConAnnotAndSettingsIO } } - for (ServiceWithParameters svc : SlivkaWSDiscoverer.getServices()) + for (ServiceWithParameters svc : SlivkaWSDiscoverer.getInstance() + .getServices()) { if (svc.getNameURI().toLowerCase().contains("aacon")) { diff --git a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java index 8454e03..fef2828 100644 --- a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java +++ b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java @@ -83,7 +83,11 @@ public class DisorderAnnotExportImport Thread.sleep(100); } SlivkaWSDiscoverer disc2 = SlivkaWSDiscoverer.getInstance(); - disc2.run(); + disc2.startDiscoverer(null); + while (disc2.isRunning()) + { + Thread.sleep(100); + } iupreds = new ArrayList<>(); for (ServiceWithParameters svc : disc2.getServices()) {