From: Mateusz Warowny Date: Wed, 15 Jul 2020 16:39:21 +0000 (+0100) Subject: JAL-3690 refactoring web-services discovery X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=2facc0e2aee62c60c28cc59277805194b306f6f9 JAL-3690 refactoring web-services discovery --- diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index cd1893d..d7a95a4 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -45,13 +45,14 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.print.PageFormat; import java.awt.print.PrinterJob; -import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Deque; import java.util.List; import java.util.Vector; @@ -68,8 +69,9 @@ import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; -import ext.vamsas.ServiceHandle; import jalview.analysis.AlignmentSorter; import jalview.analysis.AlignmentUtils; import jalview.analysis.CrossRef; @@ -155,10 +157,11 @@ import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; +import jalview.ws.ServiceChangeListener; import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; -import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; +import jalview.ws.jws2.PreferredServiceRegistry; import jalview.ws.params.ArgumentI; import jalview.ws.params.ParamDatastoreI; import jalview.ws.params.WsParamSetI; @@ -178,8 +181,9 @@ import javax.swing.JOptionPane; * @version $Revision$ */ @SuppressWarnings("serial") -public class AlignFrame extends GAlignFrame implements DropTargetListener, - IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener +public class AlignFrame extends GAlignFrame + implements DropTargetListener, IProgressIndicator, + AlignViewControllerGuiI, ColourChangeListener, ServiceChangeListener { public static final int DEFAULT_WIDTH = 700; @@ -207,8 +211,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, String fileName = null; /** - * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping - */ + * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping + */ File fileObject; /** @@ -363,8 +367,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ void init() { -// setBackground(Color.white); // BH 2019 - + // setBackground(Color.white); // BH 2019 + if (!Jalview.isHeadlessMode()) { progressBar = new ProgressBar(this.statusPanel, this.statusBar); @@ -830,55 +834,43 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return viewport; } + @Override + public void servicesChanged(WSDiscovererI discoverer, + Collection services) + { + buildWebServicesMenu(); + } + /* Set up intrinsic listeners for dynamically generated GUI bits. */ private void addServiceListeners() { - final java.beans.PropertyChangeListener thisListener; - Desktop.instance.addJalviewPropertyChangeListener("services", - thisListener = new java.beans.PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - // // System.out.println("Discoverer property change."); - // if (evt.getPropertyName().equals("services")) - { - SwingUtilities.invokeLater(new Runnable() - { - - @Override - public void run() - { - System.err.println( - "Rebuild WS Menu for service change"); - BuildWebServiceMenu(); - } - - }); - } - } - }); - addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { + WSDiscovererI discoverer = SlivkaWSDiscoverer.getInstance(); + discoverer.addServiceChangeListener(this); + } + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) + { + WSDiscovererI discoverer = Jws2Discoverer.getDiscoverer(); + discoverer.addServiceChangeListener(this); + } + // legacy event listener for compatibility with jws1 + PropertyChangeListener legacyListener = (changeEvent) -> { + buildWebServicesMenu(); + }; + Desktop.instance.addJalviewPropertyChangeListener("services",legacyListener); + + addInternalFrameListener(new InternalFrameAdapter() { @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { - // System.out.println("deregistering discoverer listener"); - Desktop.instance.removeJalviewPropertyChangeListener("services", - thisListener); + public void internalFrameClosed(InternalFrameEvent e) { + System.out.println("deregistering discoverer listener"); + SlivkaWSDiscoverer.getInstance().removeServiceChangeListener(AlignFrame.this); + Jws2Discoverer.getDiscoverer().removeServiceChangeListener(AlignFrame.this); + Desktop.instance.removeJalviewPropertyChangeListener("services", legacyListener); closeMenuItem_actionPerformed(true); } }); - // Finally, build the menu once to get current service state - new Thread(new Runnable() - { - @Override - public void run() - { - BuildWebServiceMenu(); - } - }).start(); + buildWebServicesMenu(); } /** @@ -1145,16 +1137,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new Thread(new HMMSearch(this, args)).start(); alignPanel.repaint(); } - + @Override public void jackhmmer_actionPerformed(boolean withDefaults) { - + /* * get default parameters, and (if requested) show * dialog to allow modification */ - + ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport); List args = store.getServiceParameters(); @@ -1173,7 +1165,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } new Thread(new JackHMMER(this, args)).start(); alignPanel.repaint(); - + } /** @@ -1192,31 +1184,30 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } return true; } - + @Override protected void filterByEValue_actionPerformed() { viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff")); } - + @Override protected void filterByScore_actionPerformed() { viewport.filterByScore(inputDouble("Enter Bit Score Threshold")); } - + private double inputDouble(String message) { String str = null; Double d = null; - while(d == null || d <= 0) + while (d == null || d <= 0) { str = JOptionPane.showInputDialog(this.alignPanel, message); try { d = Double.valueOf(str); - } - catch (NumberFormatException e) + } catch (NumberFormatException e) { } } @@ -1231,13 +1222,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ public boolean alignmentIsSufficient(int required) { - if (getViewport().getSequenceSelection().length < required) - { - JOptionPane.showMessageDialog(this, - MessageManager.getString("label.not_enough_sequences")); - return false; - } - return true; + if (getViewport().getSequenceSelection().length < required) + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("label.not_enough_sequences")); + return false; + } + return true; } /** @@ -1515,15 +1506,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, String shortName = title; if (shortName.indexOf(File.separatorChar) > -1) { - shortName = shortName.substring( - shortName.lastIndexOf(File.separatorChar) + 1); + shortName = shortName + .substring(shortName.lastIndexOf(File.separatorChar) + 1); } - lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName); - + lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, + shortName); + statusBar.setText(MessageManager.formatMessage( "label.successfully_saved_to_file_in_format", new Object[] { fileName, format })); - + return; } @@ -1560,16 +1552,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null; try { - String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file; - PrintWriter out = new PrintWriter( - new FileWriter(tempFilePath)); + String tempFilePath = doBackup ? backupfiles.getTempFilePath() + : file; + PrintWriter out = new PrintWriter(new FileWriter(tempFilePath)); out.print(output); out.close(); AlignFrame.this.setTitle(file); statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format.getName() })); + "label.successfully_saved_to_file_in_format", + new Object[] + { fileName, format.getName() })); lastSaveSuccessful = true; } catch (Exception ex) { @@ -1764,7 +1757,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, final JalviewFileChooser chooser = new JalviewFileChooser( jalview.bin.Cache.getProperty("LAST_DIRECTORY")); chooser.setFileView(new JalviewFileView()); - String tooltip = MessageManager.getString("label.load_jalview_annotations"); + String tooltip = MessageManager + .getString("label.load_jalview_annotations"); chooser.setDialogTitle(tooltip); chooser.setToolTipText(tooltip); chooser.setResponseHandler(0, new Runnable() @@ -2686,56 +2680,61 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return; } - Runnable okAction = new Runnable() - { - @Override - public void run() - { - SequenceI[] cut = sg.getSequences() - .toArray(new SequenceI[sg.getSize()]); - - addHistoryItem(new EditCommand( - MessageManager.getString("label.cut_sequences"), Action.CUT, - cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1, - viewport.getAlignment())); - - viewport.setSelectionGroup(null); - viewport.sendSelection(); - viewport.getAlignment().deleteGroup(sg); - - viewport.firePropertyChange("alignment", null, - viewport.getAlignment().getSequences()); - if (viewport.getAlignment().getHeight() < 1) - { - try - { - AlignFrame.this.setClosed(true); - } catch (Exception ex) - { - } - } - }}; + Runnable okAction = new Runnable() + { + @Override + public void run() + { + SequenceI[] cut = sg.getSequences() + .toArray(new SequenceI[sg.getSize()]); + + addHistoryItem(new EditCommand( + MessageManager.getString("label.cut_sequences"), Action.CUT, + cut, sg.getStartRes(), + sg.getEndRes() - sg.getStartRes() + 1, + viewport.getAlignment())); + + viewport.setSelectionGroup(null); + viewport.sendSelection(); + viewport.getAlignment().deleteGroup(sg); + + viewport.firePropertyChange("alignment", null, + viewport.getAlignment().getSequences()); + if (viewport.getAlignment().getHeight() < 1) + { + try + { + AlignFrame.this.setClosed(true); + } catch (Exception ex) + { + } + } + } + }; /* * If the cut affects all sequences, prompt for confirmation */ - boolean wholeHeight = sg.getSize() == viewport.getAlignment().getHeight(); + boolean wholeHeight = sg.getSize() == viewport.getAlignment() + .getHeight(); boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes()) + 1) == viewport.getAlignment().getWidth()) ? true : false; - if (wholeHeight && wholeWidth) - { - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop); - dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION - Object[] options = new Object[] { MessageManager.getString("action.ok"), - MessageManager.getString("action.cancel") }; - dialog.showDialog(MessageManager.getString("warn.delete_all"), - MessageManager.getString("label.delete_all"), - JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, - options, options[0]); - } else - { - okAction.run(); - } + if (wholeHeight && wholeWidth) + { + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION + Object[] options = new Object[] { + MessageManager.getString("action.ok"), + MessageManager.getString("action.cancel") }; + dialog.showDialog(MessageManager.getString("warn.delete_all"), + MessageManager.getString("label.delete_all"), + JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, + options, options[0]); + } + else + { + okAction.run(); + } } /** @@ -3607,7 +3606,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, JLabel textLabel = new JLabel(); textLabel.setText(content); textLabel.setBackground(Color.WHITE); - + pane = new JPanel(new BorderLayout()); ((JPanel) pane).setOpaque(true); pane.setBackground(Color.WHITE); @@ -3737,8 +3736,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * otherwise set the chosen colour scheme (or null for 'None') */ ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name, - viewport, - viewport.getAlignment(), viewport.getHiddenRepSequences()); + viewport, viewport.getAlignment(), + viewport.getHiddenRepSequences()); changeColour(cs); } @@ -3913,7 +3912,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignPanel.paintAlignment(true, false); } - + /** * DOCUMENT ME! * @@ -4309,7 +4308,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, chooser.setToolTipText( MessageManager.getString("label.load_tree_file")); - chooser.setResponseHandler(0,new Runnable() + chooser.setResponseHandler(0, new Runnable() { @Override public void run() @@ -4404,205 +4403,259 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return tp; } - private boolean buildingMenu = false; - /** - * Generates menu items and listener event actions for web service clients - * + * Schedule the web services menu rebuild to the event dispatch thread. */ - public void BuildWebServiceMenu() + public void buildWebServicesMenu() { - while (buildingMenu) - { - try + SwingUtilities.invokeLater(() -> { + webService.removeAll(); + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - System.err.println("Waiting for building menu to finish."); - Thread.sleep(10); - } catch (Exception e) + SlivkaWSDiscoverer discoverer = SlivkaWSDiscoverer.getInstance(); + JMenu submenu = new JMenu("Slivka"); + buildWebServicesMenu(discoverer, submenu); + webService.add(submenu); + } + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { + WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); + JMenu submenu = new JMenu("JABAWS"); + buildWebServicesMenu(jws2servs, submenu); + webService.add(submenu); } + }); + } + + /** + * Constructs the web services menu for the given discoverer under the + * specified menu. This method must be called on the EDT + * + * @param discoverer + * the discoverer used to build the menu + * @param menu + * parent component which the elements will be attached to + */ + private void buildWebServicesMenu(WSDiscovererI discoverer, JMenu menu) + { + if (discoverer.hasServices()) + { + PreferredServiceRegistry.getRegistry().populateWSMenuEntry( + discoverer.getServices(), null, menu, this, null); } - final AlignFrame me = this; - buildingMenu = true; - new Thread(new Runnable() + if (discoverer.isRunning()) { - @Override - public void run() - { - final List legacyItems = new ArrayList<>(); - try - { - // System.err.println("Building ws menu again " - // + Thread.currentThread()); - // TODO: add support for context dependent disabling of services based - // on - // alignment and current selection - // TODO: add additional serviceHandle parameter to specify abstract - // handler - // class independently of AbstractName - // TODO: add in rediscovery GUI function to restart discoverer - // TODO: group services by location as well as function and/or - // introduce - // object broker mechanism. - final Vector wsmenu = new Vector<>(); - final IProgressIndicator af = me; - - /* - * do not i18n these strings - they are hard-coded in class - * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and - * SequenceAnnotationWSClient.initSequenceAnnotationWSClient() - */ - final JMenu msawsmenu = new JMenu("Alignment"); - final JMenu secstrmenu = new JMenu( - "Secondary Structure Prediction"); - final JMenu seqsrchmenu = new JMenu("Sequence Database Search"); - final JMenu analymenu = new JMenu("Analysis"); - final JMenu dismenu = new JMenu("Protein Disorder"); - // JAL-940 - only show secondary structure prediction services from - // the legacy server - if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) - // && - Discoverer.services != null && (Discoverer.services.size() > 0)) - { - // TODO: refactor to allow list of AbstractName/Handler bindings to - // be - // stored or retrieved from elsewhere - // No MSAWS used any more: - // Vector msaws = null; // (Vector) - // Discoverer.services.get("MsaWS"); - Vector secstrpr = Discoverer.services - .get("SecStrPred"); - if (secstrpr != null) - { - // Add any secondary structure prediction services - for (int i = 0, j = secstrpr.size(); i < j; i++) - { - final ext.vamsas.ServiceHandle sh = secstrpr - .get(i); - jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer - .getServiceClient(sh); - int p = secstrmenu.getItemCount(); - impl.attachWSMenuEntry(secstrmenu, me); - int q = secstrmenu.getItemCount(); - for (int litm = p; litm < q; litm++) - { - legacyItems.add(secstrmenu.getItem(litm)); - } - } - } - } - - // Add all submenus in the order they should appear on the web - // services menu - wsmenu.add(msawsmenu); - wsmenu.add(secstrmenu); - wsmenu.add(dismenu); - wsmenu.add(analymenu); - // No search services yet - // wsmenu.add(seqsrchmenu); - - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - try - { - webService.removeAll(); - // first, add discovered services onto the webservices menu - if (wsmenu.size() > 0) - { - for (int i = 0, j = wsmenu.size(); i < j; i++) - { - webService.add(wsmenu.get(i)); - } - } - else - { - webService.add(me.webServiceNoServices); - } - // TODO: move into separate menu builder class. - boolean new_sspred = false; - - if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) - { - WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); - if (jws2servs != null) - { - if (jws2servs.hasServices()) - { - jws2servs.attachWSMenuEntry(webService, me); - for (ServiceWithParameters sv : jws2servs.getServices()) - { - if (sv.getName().toLowerCase().contains("jpred")) - { - for (JMenuItem jmi : legacyItems) - { - jmi.setVisible(false); - } - } - } - - } - if (jws2servs.isRunning()) - { - JMenuItem tm = new JMenuItem( - "Still discovering JABA Services"); - tm.setEnabled(false); - webService.add(tm); - } - } - } - - if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) - { - 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); - } - } - } + JMenuItem item = new JMenuItem("Service discovery in progress."); + item.setEnabled(false); + menu.add(item); + } + else if (!discoverer.hasServices()) + { + JMenuItem item = new JMenuItem("No services available."); + item.setEnabled(false); + menu.add(item); + } + } - build_urlServiceMenu(me.webService); - build_fetchdbmenu(webService); - for (JMenu item : wsmenu) - { - if (item.getItemCount() == 0) - { - item.setEnabled(false); - } - else - { - item.setEnabled(true); - } - } - } catch (Exception e) - { - Cache.log.debug( - "Exception during web service menu building process.", - e); - } - } - }); - } catch (Exception e) - { - } - buildingMenu = false; - } - }).start(); +// private boolean buildingMenu = false; - } + /** + * Generates menu items and listener event actions for web service clients + * + */ +// public void BuildWebServiceMenu() +// { +// while (buildingMenu) +// { +// try +// { +// System.err.println("Waiting for building menu to finish."); +// Thread.sleep(10); +// } catch (Exception e) +// { +// } +// } +// final AlignFrame me = this; +// buildingMenu = true; +// new Thread(new Runnable() +// { +// @Override +// public void run() +// { +// final List legacyItems = new ArrayList<>(); +// try +// { +// // System.err.println("Building ws menu again " +// // + Thread.currentThread()); +// // TODO: add support for context dependent disabling of services based +// // on +// // alignment and current selection +// // TODO: add additional serviceHandle parameter to specify abstract +// // handler +// // class independently of AbstractName +// // TODO: add in rediscovery GUI function to restart discoverer +// // TODO: group services by location as well as function and/or +// // introduce +// // object broker mechanism. +// final Vector wsmenu = new Vector<>(); +// final IProgressIndicator af = me; +// +// /* +// * do not i18n these strings - they are hard-coded in class +// * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and +// * SequenceAnnotationWSClient.initSequenceAnnotationWSClient() +// */ +// final JMenu msawsmenu = new JMenu("Alignment"); +// final JMenu secstrmenu = new JMenu( +// "Secondary Structure Prediction"); +// final JMenu seqsrchmenu = new JMenu("Sequence Database Search"); +// final JMenu analymenu = new JMenu("Analysis"); +// final JMenu dismenu = new JMenu("Protein Disorder"); +// // JAL-940 - only show secondary structure prediction services from +// // the legacy server +// if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) +// // && +// Discoverer.services != null && (Discoverer.services.size() > 0)) +// { +// // TODO: refactor to allow list of AbstractName/Handler bindings to +// // be +// // stored or retrieved from elsewhere +// // No MSAWS used any more: +// // Vector msaws = null; // (Vector) +// // Discoverer.services.get("MsaWS"); +// Vector secstrpr = Discoverer.services +// .get("SecStrPred"); +// if (secstrpr != null) +// { +// // Add any secondary structure prediction services +// for (int i = 0, j = secstrpr.size(); i < j; i++) +// { +// final ext.vamsas.ServiceHandle sh = secstrpr.get(i); +// jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer +// .getServiceClient(sh); +// int p = secstrmenu.getItemCount(); +// impl.attachWSMenuEntry(secstrmenu, me); +// int q = secstrmenu.getItemCount(); +// for (int litm = p; litm < q; litm++) +// { +// legacyItems.add(secstrmenu.getItem(litm)); +// } +// } +// } +// } +// +// // Add all submenus in the order they should appear on the web +// // services menu +// wsmenu.add(msawsmenu); +// wsmenu.add(secstrmenu); +// wsmenu.add(dismenu); +// wsmenu.add(analymenu); +// // No search services yet +// // wsmenu.add(seqsrchmenu); +// +// javax.swing.SwingUtilities.invokeLater(new Runnable() +// { +// @Override +// public void run() +// { +// try +// { +// webService.removeAll(); +// // first, add discovered services onto the webservices menu +// if (wsmenu.size() > 0) +// { +// for (int i = 0, j = wsmenu.size(); i < j; i++) +// { +// webService.add(wsmenu.get(i)); +// } +// } +// else +// { +// webService.add(me.webServiceNoServices); +// } +// // TODO: move into separate menu builder class. +// boolean new_sspred = false; +// +// if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) +// { +// WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); +// if (jws2servs != null) +// { +// if (jws2servs.hasServices()) +// { +// jws2servs.attachWSMenuEntry(webService, me); +// for (ServiceWithParameters sv : jws2servs +// .getServices()) +// { +// if (sv.getName().toLowerCase().contains("jpred")) +// { +// for (JMenuItem jmi : legacyItems) +// { +// jmi.setVisible(false); +// } +// } +// } +// +// } +// if (jws2servs.isRunning()) +// { +// JMenuItem tm = new JMenuItem( +// "Still discovering JABA Services"); +// tm.setEnabled(false); +// webService.add(tm); +// } +// } +// } +// +// if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) +// { +// 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) +// { +// if (item.getItemCount() == 0) +// { +// item.setEnabled(false); +// } +// else +// { +// item.setEnabled(true); +// } +// } +// } catch (Exception e) +// { +// Cache.log.debug( +// "Exception during web service menu building process.", +// e); +// } +// } +// }); +// } catch (Exception e) +// { +// } +// buildingMenu = false; +// } +// }).start(); +// +// } /** * construct any groupURL type service menu entries. @@ -4879,10 +4932,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (protocol == DataSourceType.FILE) { File fl; - if (file instanceof File) { + if (file instanceof File) + { fl = (File) file; Platform.cacheFileData(fl); - } else { + } + else + { fl = new File(fileName); } pdbfn = fl.getName(); @@ -6128,6 +6184,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } private Rectangle lastFeatureSettingsBounds = null; + @Override public void setFeatureSettingsGeometry(Rectangle bounds) { diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index a99bab9..d8e3bbb 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -59,8 +59,11 @@ import java.util.Hashtable; import java.util.List; import java.util.ListIterator; import java.util.Vector; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.Semaphore; import javax.swing.AbstractAction; @@ -2631,10 +2634,9 @@ public class Desktop extends jalview.jbgui.GDesktop public void startServiceDiscovery(boolean blocking) { - boolean alive = true; - Thread t0 = null, t1 = null, t2 = null, t3 = null; + var tasks = new ArrayList>(); // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release - if (true) + { // todo: changesupport handlers need to be transferred if (discoverer == null) @@ -2645,53 +2647,32 @@ public class Desktop extends jalview.jbgui.GDesktop } // JAL-940 - disabled JWS1 service configuration - always start discoverer // until we phase out completely - (t0 = new Thread(discoverer)).start(); + var f = new FutureTask(discoverer, null); + new Thread(f).start(); + tasks.add(f); } if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = startServiceDiscovery( - jalview.ws.jws2.Jws2Discoverer.getDiscoverer(), false); + tasks.add(jalview.ws.jws2.Jws2Discoverer.getDiscoverer().startDiscoverer()); } if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - // start slivka discovery - t3 = startServiceDiscovery( - jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance(), false); + tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer()); } if (blocking) { - while (alive) - { + for (Future task : tasks) { try { - Thread.sleep(15); + // block until all discovery tasks are done + task.get(); } catch (Exception e) { + e.printStackTrace(); } - // 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()); - } - } - } - - public Thread startServiceDiscovery(WSDiscovererI discoverer, - boolean blocking) - { - Thread thread = discoverer.startDiscoverer(changeSupport); - if (blocking) - { - try - { - thread.join(); - } catch (InterruptedException e) - { - e.printStackTrace(); } } - return thread; } /** diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java index f4f6a9a..0743d58 100644 --- a/src/jalview/gui/SlivkaPreferences.java +++ b/src/jalview/gui/SlivkaPreferences.java @@ -29,6 +29,7 @@ import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; @@ -306,12 +307,18 @@ public class SlivkaPreferences extends JPanel // Discoverer buttons action listeners private ActionListener refreshServicesAction = (ActionEvent e) -> { + progressBar.setVisible(true); new Thread(() -> { - progressBar.setVisible(true); Cache.log.info("Requesting service reload"); - Desktop.instance.startServiceDiscovery(discoverer, true); - Cache.log.info("Reloading done"); - progressBar.setVisible(false); + var task = discoverer.startDiscoverer(); + try { + task.get(); + Cache.log.info("Reloading done"); + } catch (Exception exc) { + Cache.log.error("Reloading failed", exc); + } finally { + SwingUtilities.invokeLater(() -> progressBar.setVisible(false)); + } }).start(); }; diff --git a/src/jalview/gui/WsJobParameters.java b/src/jalview/gui/WsJobParameters.java index 0ddb9ff..d359135 100644 --- a/src/jalview/gui/WsJobParameters.java +++ b/src/jalview/gui/WsJobParameters.java @@ -1044,7 +1044,7 @@ public class WsJobParameters extends JPanel implements ItemListener, } for (AlignFrame alignFrame : Desktop.getAlignFrames()) { - alignFrame.BuildWebServiceMenu(); + alignFrame.buildWebServicesMenu(); } } diff --git a/src/jalview/ws/ServiceChangeListener.java b/src/jalview/ws/ServiceChangeListener.java new file mode 100644 index 0000000..98e15b9 --- /dev/null +++ b/src/jalview/ws/ServiceChangeListener.java @@ -0,0 +1,13 @@ +package jalview.ws; + +import java.util.Collection; +import java.util.EventListener; + +import jalview.ws.api.ServiceWithParameters; + +@FunctionalInterface +public interface ServiceChangeListener extends EventListener +{ + public void servicesChanged(WSDiscovererI discoverer, + Collection services); +} diff --git a/src/jalview/ws/WSDiscovererI.java b/src/jalview/ws/WSDiscovererI.java index e5b94f0..b8a1d43 100644 --- a/src/jalview/ws/WSDiscovererI.java +++ b/src/jalview/ws/WSDiscovererI.java @@ -2,11 +2,11 @@ package jalview.ws; import jalview.ws.api.ServiceWithParameters; -import java.beans.PropertyChangeListener; import java.net.URL; import java.util.List; +import java.util.concurrent.Future; -public interface WSDiscovererI extends WSMenuEntryProviderI +public interface WSDiscovererI { public static final int STATUS_OK = 1; public static final int STATUS_NO_SERVICES = 0; @@ -22,9 +22,12 @@ public interface WSDiscovererI extends WSMenuEntryProviderI public boolean testServiceUrl(URL url); public int getServerStatusFor(String url); + + public void addServiceChangeListener(ServiceChangeListener listener); + + public void removeServiceChangeListener(ServiceChangeListener listener); - // TODO: should not return Thread but something generic providing isRunning method - public Thread startDiscoverer(PropertyChangeListener changeListener); + public Future startDiscoverer(); public String getErrorMessages(); diff --git a/src/jalview/ws/jws1/Discoverer.java b/src/jalview/ws/jws1/Discoverer.java index bee9fad..7ab8117 100644 --- a/src/jalview/ws/jws1/Discoverer.java +++ b/src/jalview/ws/jws1/Discoverer.java @@ -379,17 +379,8 @@ public class Discoverer implements Runnable @Override public void run() { - final Discoverer discoverer = this; - Thread discoverThread = new Thread() - { - @Override - public void run() - { - Discoverer.doDiscovery(); - discoverer.discoverServices(); - } - }; - discoverThread.start(); + Discoverer.doDiscovery(); + discoverServices(); } /** diff --git a/src/jalview/ws/jws2/Jws2Discoverer.java b/src/jalview/ws/jws2/Jws2Discoverer.java index 30c1cb7..73d3700 100644 --- a/src/jalview/ws/jws2/Jws2Discoverer.java +++ b/src/jalview/ws/jws2/Jws2Discoverer.java @@ -23,6 +23,7 @@ package jalview.ws.jws2; import jalview.bin.Cache; import jalview.gui.AlignFrame; import jalview.util.MessageManager; +import jalview.ws.ServiceChangeListener; import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws2.jabaws2.Jws2Instance; @@ -34,11 +35,16 @@ import java.beans.PropertyChangeSupport; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import javax.swing.JMenu; @@ -72,9 +78,8 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable // preferred url has precedence over others private String preferredUrl; - - private PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); + + private Set serviceListeners = new CopyOnWriteArraySet<>(); private Vector invalidServiceUrls = null; @@ -85,8 +90,8 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable private volatile boolean running = false; private volatile boolean aborted = false; - - private Thread oldthread = null; + + private volatile Thread oldthread = null; /** * holds list of services. @@ -100,28 +105,25 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable { } - /** - * change listeners are notified of "services" property changes - * - * @param listener - * to be added that consumes new services Hashtable object. - */ - public void addPropertyChangeListener( - java.beans.PropertyChangeListener listener) + + @Override + public void addServiceChangeListener(ServiceChangeListener listener) { - changeSupport.addPropertyChangeListener(listener); + serviceListeners.add(listener); } - /** - * - * - * @param listener - * to be removed - */ - public void removePropertyChangeListener( - java.beans.PropertyChangeListener listener) + @Override + public void removeServiceChangeListener(ServiceChangeListener listener) { - changeSupport.removePropertyChangeListener(listener); + serviceListeners.remove(listener); + } + + private void notifyServiceListeners(List services) + { + if (services == null) services = this.services; + for (var listener : serviceListeners) { + listener.servicesChanged(this, services); + } } /** @@ -176,13 +178,11 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable ignoredServices.add(ignored); } - changeSupport.firePropertyChange("services", services, - new Vector()); + notifyServiceListeners(Collections.emptyList()); oldthread = Thread.currentThread(); try { - Class foo = getClass().getClassLoader() - .loadClass("compbio.ws.client.Jws2Client"); + getClass().getClassLoader().loadClass("compbio.ws.client.Jws2Client"); } catch (ClassNotFoundException e) { System.err.println( @@ -287,8 +287,7 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable } oldthread = null; running = false; - changeSupport.firePropertyChange("services", new Vector(), - services); + notifyServiceListeners(services); } /** @@ -325,30 +324,6 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable } /** - * attach all available web services to the appropriate submenu in the given - * JMenu - */ - @Override - public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame) - { - if (running || services == null || services.size() == 0) - { - return; - } - // dynamically regenerate service list. - populateWSMenuEntry(wsmenu, alignFrame, null); - } - - private void populateWSMenuEntry(JMenu jws2al, - final AlignFrame alignFrame, String typeFilter) - { - PreferredServiceRegistry.getRegistry().populateWSMenuEntry( - getServices(), - changeSupport, jws2al, - alignFrame, typeFilter); - } - - /** * * @param args * @j2sIgnore @@ -363,37 +338,28 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable testUrls.add(url); } } - Thread runner = getDiscoverer() - .startDiscoverer(new PropertyChangeListener() - { - - @Override - public void propertyChange(PropertyChangeEvent evt) - { - if (getDiscoverer().services != null) - { - System.out.println("Changesupport: There are now " - + getDiscoverer().services.size() + " services"); - int i = 1; - for (ServiceWithParameters instance : getDiscoverer().services) - { - System.out.println("Service " + i++ + " " - + instance.getClass() + "@" - + instance.getHostURL() - + ": " + instance.getActionText()); - } - - } - } - }); - while (runner.isAlive()) - { - try - { - Thread.sleep(50); - } catch (InterruptedException e) + var discoverer = getDiscoverer(); + discoverer.addServiceChangeListener((_discoverer, _services) -> { + if (discoverer.services != null) { + System.out.println("Changesupport: There are now " + + discoverer.services.size() + " services"); + int i = 1; + for (ServiceWithParameters instance : discoverer.services) + { + System.out.println( + "Service " + i++ + " " + instance.getClass() + + "@" + instance.getHostURL() + ": " + + instance.getActionText()); + } + } + }); + try + { + discoverer.startDiscoverer().get(); + } catch (InterruptedException | ExecutionException e) + { } try { @@ -513,8 +479,7 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable @Override public Vector getServices() { - return (services == null) ? new Vector<>() - : new Vector<>(services); + return (services == null) ? new Vector<>() : new Vector<>(services); } /** @@ -573,7 +538,7 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable * @return new thread */ @Override - public Thread startDiscoverer(PropertyChangeListener changeSupport2) + public FutureTask startDiscoverer() { /* if (restart()) { @@ -589,10 +554,9 @@ public class Jws2Discoverer implements WSDiscovererI, Runnable { setAborted(true); } - addPropertyChangeListener(changeSupport2); - Thread thr = new Thread(this); - thr.start(); - return thr; + FutureTask task = new FutureTask<>(this, this); + new Thread(task).start(); + return task; } /** diff --git a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java index 7a41431..0e66c28 100644 --- a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java +++ b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java @@ -1,20 +1,23 @@ package jalview.ws.slivkaws; import jalview.bin.Cache; -import jalview.gui.AlignFrame; +import jalview.ws.ServiceChangeListener; 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.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.List; - -import javax.swing.JMenu; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import uk.ac.dundee.compbio.slivkaclient.SlivkaClient; import uk.ac.dundee.compbio.slivkaclient.SlivkaService; @@ -42,78 +45,39 @@ public class SlivkaWSDiscoverer implements WSDiscovererI return instance; } - private PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); - + private Set serviceListeners = new CopyOnWriteArraySet<>(); + @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); - + public void addServiceChangeListener(ServiceChangeListener l) { + serviceListeners.add(l); } - - volatile boolean ready = false; - - volatile Thread discovererThread = null; - - private class DiscovererThread extends Thread - { - private Thread oldThread; - - DiscovererThread(Thread oldThread) - { - super(); - this.oldThread = oldThread; - } - - @Override - public void run() - { - if (oldThread != null) - { - oldThread.interrupt(); - try - { - oldThread.join(); - } catch (InterruptedException e) - { - return; - } finally - { - oldThread = null; - } - } - ready = false; - reloadServices(); - ready = !isInterrupted(); + + @Override + public void removeServiceChangeListener(ServiceChangeListener l) { + serviceListeners.remove(l); + } + + public void notifyServiceListeners(List services) { + for (var listener : serviceListeners) { + listener.servicesChanged(this, services); } } - Thread discoverer = null; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + private Vector> discoveryTasks = new Vector<>(); - @Override - public Thread startDiscoverer(PropertyChangeListener changeListener) + public Future startDiscoverer() { - changeSupport.addPropertyChangeListener(changeListener); - ready = false; - (discovererThread = new DiscovererThread(discovererThread)).start(); - return discovererThread; + FutureTask task = new FutureTask<>(this::reloadServices, this); + discoveryTasks.add(task); + executor.execute(task); + return task; } - private void reloadServices() + private List reloadServices() { Cache.log.info("Reloading Slivka services"); - changeSupport.firePropertyChange("services", services, List.of()); + notifyServiceListeners(Collections.emptyList()); ArrayList instances = new ArrayList<>(); for (String url : getServiceUrls()) @@ -152,14 +116,15 @@ public class SlivkaWSDiscoverer implements WSDiscovererI } } catch (IOException e) { + e.printStackTrace(); continue; } } services = instances; - changeSupport.firePropertyChange("services", List.of(), services); - + notifyServiceListeners(instances); Cache.log.info("Slivka services reloading finished"); + return instances; } @Override @@ -171,14 +136,13 @@ public class SlivkaWSDiscoverer implements WSDiscovererI @Override public boolean hasServices() { - return ready == true && services.size() > 0; + return !isRunning() && services.size() > 0; } @Override public boolean isRunning() { - return discovererThread == null || discovererThread.isAlive() - || discovererThread.getState() == Thread.State.NEW; + return !discoveryTasks.stream().allMatch(Future::isDone); } @Override diff --git a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java index fef2828..372dcb2 100644 --- a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java +++ b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java @@ -83,7 +83,7 @@ public class DisorderAnnotExportImport Thread.sleep(100); } SlivkaWSDiscoverer disc2 = SlivkaWSDiscoverer.getInstance(); - disc2.startDiscoverer(null); + disc2.startDiscoverer(); while (disc2.isRunning()) { Thread.sleep(100);