import jalview.ws.seqfetcher.DbSourceProxy;
import java.awt.BorderLayout;
+import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
+import javajs.async.AsyncSwingWorker;
+
/**
* A panel where the use may choose a database source, and enter one or more
* accessions, to retrieve entries from the database.
* instead to perform the search and selection.
*/
@SuppressWarnings("serial")
-public class SequenceFetcher extends JPanel implements Runnable
+public class SequenceFetcher extends JPanel
{
JLabel exampleAccession;
frame = new JInternalFrame();
frame.setContentPane(this);
- Desktop.addInternalFrame(frame, getFrameTitle(), true, 400,
- Platform.isAMacAndNotJS() ? 240 : 180);
+ Desktop.addInternalFrame(frame, getFrameTitle(), true, 400,
+ Platform.isAMacAndNotJS() ? 240 : 180);
}
private String getFrameTitle()
text = text.replace(",", ";");
}
text = text.replaceAll("(\\s|[; ])+", ";");
- if (!t0.equals(text))
+ if (!t0.equals(text))
{
- textArea.setText(text);
+ textArea.setText(text);
}
if (text.isEmpty())
{
okBtn.setEnabled(false);
closeBtn.setEnabled(false);
backBtn.setEnabled(false);
+ fetch(null, true);
+ }
- Thread worker = new Thread(this);
- worker.start();
+ public void fetch(String ids, boolean isAsync)
+ {
+ isAsync &= Platform.isJS();
+ if (ids == null)
+ {
+ ids = textArea.getText();
+ }
+ else
+ {
+ textArea.setText(ids);
+ }
+ Component parent = null; // or this
+ String title = null; // or some title for the progress monitor
+ int min = AsyncFetchTask.STATE_INIT;
+ int max = AsyncFetchTask.STATE_DONE;
+ int msDelay = (isAsync ? 5 : 0);
+ new AsyncFetchTask(ids, parent, title, msDelay, min, max).execute();
}
- private void resetDialog()
+
+ protected void resetDialog()
{
exampleBtn.setEnabled(true);
textArea.setEnabled(true);
backBtn.setEnabled(parentSearchPanel != null);
}
- @Override
- public void run()
+ /**
+ * This asynchronous class allows for a single-threaded state machine
+ * SwingWorker to process a list of requests from multiple sources.
+ *
+ * A standard ProcessMonitor could be attached to this task, but it is
+ * currently not.
+ *
+ * @author hansonr
+ *
+ */
+ private class AsyncFetchTask extends AsyncSwingWorker
{
- boolean addToLast = false;
- List<String> aresultq = new ArrayList<>();
- List<String> presultTitle = new ArrayList<>();
- List<AlignmentI> presult = new ArrayList<>();
- List<AlignmentI> aresult = new ArrayList<>();
- List<DbSourceProxy> sources = jalview.ws.SequenceFetcher.getInstance()
- .getSourceProxy((String) database.getSelectedItem());
- Iterator<DbSourceProxy> proxies = sources.iterator();
- String[] qries = textArea.getText().trim().split(";");
- List<String> nextFetch = Arrays.asList(qries);
- Iterator<String> en = Arrays.asList(new String[0]).iterator();
- int nqueries = qries.length;
-
- FeatureSettingsModelI preferredFeatureColours = null;
- while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0))
- {
- if (!en.hasNext() && nextFetch.size() > 0)
- {
- en = nextFetch.iterator();
- nqueries = nextFetch.size();
- // save the remaining queries in the original array
- qries = nextFetch.toArray(new String[nqueries]);
- nextFetch = new ArrayList<>();
- }
- DbSourceProxy proxy = proxies.next();
- try
+ private boolean addToLast = false;
+
+ private List<String> aresultq = new ArrayList<>();
+
+ private List<String> presultTitle = new ArrayList<>();
+
+ private List<AlignmentI> presult = new ArrayList<>();
+
+ private List<AlignmentI> aresult = new ArrayList<>();
+
+ private FeatureSettingsModelI preferredFeatureColours = null;
+
+ private List<DbSourceProxy> sources;
+
+ private Iterator<DbSourceProxy> sourceIterator;
+
+ private String[] fetchArray;
+
+ private List<String> fetchList;
+
+ private Iterator<String> fetchIterator;
+
+ private int fetchCount;
+
+ private DbSourceProxy source;
+
+ private String ids;
+
+ public AsyncFetchTask(String ids, Component owner, String title,
+ int delayMillis,
+ int min, int max)
+ {
+ super(owner, title, delayMillis, min, max);
+ this.ids = ids;
+ }
+
+ @Override
+ public void initAsync()
+ {
+ sources = jalview.ws.SequenceFetcher.getInstance()
+ .getSourceProxy((String) database.getSelectedItem());
+ sourceIterator = sources.iterator();
+ fetchArray = ids.trim().split(";");
+ fetchList = Arrays.asList(fetchArray);
+ }
+
+ private final static int STATE_INIT = 0;
+
+ private final static int STATE_NEXT_SOURCE = 10;
+
+ private final static int STATE_FETCH_SINGLE = 30;
+
+ private final static int STATE_FETCH_MULTIPLE = 40;
+
+ private final static int STATE_PROCESS = 50;
+
+ private final static int STATE_PARSE_RESULTS = 80;
+
+ private final static int STATE_DONE = 100;
+
+ @Override
+ public int doInBackgroundAsync(int progress)
+ {
+ switch (progress)
{
- // update status
- guiWindow.setProgressBar(MessageManager.formatMessage(
+ case STATE_INIT:
+ case STATE_NEXT_SOURCE:
+ boolean doneFetching = (fetchIterator == null
+ || !fetchIterator.hasNext());
+ boolean havePending = (fetchList.size() > 0);
+ if (!sourceIterator.hasNext() || doneFetching && !havePending)
+ {
+ showProgress((presult.size() > 0)
+ ? MessageManager.getString("status.parsing_results")
+ : MessageManager.getString("status.processing"));
+ return STATE_PARSE_RESULTS;
+ }
+ source = sourceIterator.next();
+ if (doneFetching)
+ {
+ // if we are here, we must have some pending still
+ fetchCount = fetchList.size();
+ fetchIterator = fetchList.iterator();
+ // save the remaining queries in the original array
+ fetchArray = fetchList.toArray(new String[fetchCount]);
+ // and clear the
+ fetchList = new ArrayList<>();
+ }
+ showProgress(MessageManager.formatMessage(
"status.fetching_sequence_queries_from", new String[]
- { Integer.valueOf(nqueries).toString(),
- proxy.getDbName() }),
- Thread.currentThread().hashCode());
- if (proxy.getMaximumQueryCount() == 1)
+ { Integer.valueOf(fetchCount).toString(),
+ source.getDbName() }));
+ return (source.getMaximumQueryCount() == 1 ? STATE_FETCH_SINGLE
+ : STATE_FETCH_MULTIPLE);
+ case STATE_FETCH_SINGLE:
+ if (fetchIterator.hasNext())
{
- /*
- * proxy only handles one accession id at a time
- */
- while (en.hasNext())
+ // source only handles one accession id at a time
+ try
+ {
+ if (delayMillis == 0)
+ {
+ // for CrossRef2xmlTest only
+ Thread.sleep(5);
+ }
+ String accession = fetchIterator.next();
+ if (!fetchSingleAccession(source, accession, aresultq, aresult))
+ {
+ fetchList.add(accession);
+ }
+ } catch (Throwable e)
{
- String acc = en.next();
- if (!fetchSingleAccession(proxy, acc, aresultq, aresult))
+ if (!showError(e))
{
- nextFetch.add(acc);
+ return STATE_DONE;
}
}
+ return STATE_FETCH_SINGLE;
}
- else
- {
- /*
- * proxy can fetch multiple accessions at one time
- */
- fetchMultipleAccessions(proxy, en, aresultq, aresult, nextFetch);
- }
- } catch (Exception e)
- {
- showErrorMessage("Error retrieving " + textArea.getText() + " from "
- + database.getSelectedItem());
- // error
- // +="Couldn't retrieve sequences from "+database.getSelectedItem();
- System.err.println("Retrieval failed for source ='"
- + database.getSelectedItem() + "' and query\n'"
- + textArea.getText() + "'\n");
- e.printStackTrace();
- } catch (OutOfMemoryError e)
- {
- showErrorMessage("Out of Memory when retrieving "
- + textArea.getText() + " from " + database.getSelectedItem()
- + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n");
- e.printStackTrace();
- } catch (Error e)
- {
- showErrorMessage("Serious Error retrieving " + textArea.getText()
- + " from " + database.getSelectedItem());
- e.printStackTrace();
- }
-
- // Stack results ready for opening in alignment windows
- if (aresult != null && aresult.size() > 0)
- {
- FeatureSettingsModelI proxyColourScheme = proxy
- .getFeatureColourScheme();
- if (proxyColourScheme != null)
+ return STATE_PROCESS;
+ case STATE_FETCH_MULTIPLE:
+ // proxy can fetch multiple accessions at one time
+ try
{
- preferredFeatureColours = proxyColourScheme;
- }
-
- AlignmentI ar = null;
- if (proxy.isAlignmentSource())
+ fetchMultipleAccessions(source, fetchIterator, aresultq, aresult,
+ fetchList);
+ } catch (Throwable e)
{
- addToLast = false;
- // new window for each result
- while (aresult.size() > 0)
+ if (!showError(e))
{
- presult.add(aresult.remove(0));
- presultTitle.add(
- aresultq.remove(0) + " " + getDefaultRetrievalTitle());
+ return STATE_DONE;
}
}
- else
+ return STATE_PROCESS;
+ case STATE_PROCESS:
+ // Stack results ready for opening in alignment windows
+ if (aresult != null && aresult.size() > 0)
{
- String titl = null;
- if (addToLast && presult.size() > 0)
+ FeatureSettingsModelI proxyColourScheme = source
+ .getFeatureColourScheme();
+ if (proxyColourScheme != null)
+ {
+ preferredFeatureColours = proxyColourScheme;
+ }
+
+ AlignmentI ar = null;
+ if (source.isAlignmentSource())
{
- ar = presult.remove(presult.size() - 1);
- titl = presultTitle.remove(presultTitle.size() - 1);
+ addToLast = false;
+ // new window for each result
+ while (aresult.size() > 0)
+ {
+ presult.add(aresult.remove(0));
+ presultTitle.add(aresultq.remove(0) + " "
+ + getDefaultRetrievalTitle());
+ }
}
- // concatenate all results in one window
- while (aresult.size() > 0)
+ else
{
- if (ar == null)
+ String titl = null;
+ if (addToLast && presult.size() > 0)
{
- ar = aresult.remove(0);
+ ar = presult.remove(presult.size() - 1);
+ titl = presultTitle.remove(presultTitle.size() - 1);
}
- else
+ // concatenate all results in one window
+ while (aresult.size() > 0)
{
- ar.append(aresult.remove(0));
+ if (ar == null)
+ {
+ ar = aresult.remove(0);
+ }
+ else
+ {
+ ar.append(aresult.remove(0));
+ }
}
+ addToLast = true;
+ presult.add(ar);
+ presultTitle.add(titl);
}
- addToLast = true;
- presult.add(ar);
- presultTitle.add(titl);
}
+ showProgress(MessageManager.getString("status.finshed_querying"));
+ return STATE_NEXT_SOURCE;
+ case STATE_PARSE_RESULTS:
+ while (presult.size() > 0)
+ {
+ parseResult(presult.remove(0), presultTitle.remove(0), null,
+ preferredFeatureColours);
+ }
+ break;
}
- guiWindow.setProgressBar(
- MessageManager.getString("status.finshed_querying"),
- Thread.currentThread().hashCode());
+ return STATE_DONE;
}
- guiWindow
- .setProgressBar(
- (presult.size() > 0)
- ? MessageManager
- .getString("status.parsing_results")
- : MessageManager.getString("status.processing"),
- Thread.currentThread().hashCode());
- // process results
- while (presult.size() > 0)
- {
- parseResult(presult.remove(0), presultTitle.remove(0), null,
- preferredFeatureColours);
+
+ private void showProgress(String msg)
+ {
+ guiWindow.setProgressBar(msg, Thread.currentThread().hashCode());
}
- // only remove visual delay after we finished parsing.
- guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
- if (nextFetch.size() > 0)
- {
- StringBuffer sb = new StringBuffer();
- sb.append("Didn't retrieve the following "
- + (nextFetch.size() == 1 ? "query"
- : nextFetch.size() + " queries")
- + ": \n");
- int l = sb.length(), lr = 0;
- for (String s : nextFetch)
+
+ @Override
+ public void doneAsync()
+ {
+ showProgress(null);
+ if (fetchList.size() > 0)
{
- if (l != sb.length())
- {
- sb.append("; ");
- }
- if (lr - sb.length() > 40)
+ StringBuffer sb = new StringBuffer();
+ sb.append("Didn't retrieve the following "
+ + (fetchList.size() == 1 ? "query"
+ : fetchList.size() + " queries")
+ + ": \n");
+ int l = sb.length(), lr = 0;
+ for (String s : fetchList)
{
- sb.append("\n");
+ if (l != sb.length())
+ {
+ sb.append("; ");
+ }
+ if (lr - sb.length() > 40)
+ {
+ sb.append("\n");
+ }
+ sb.append(s);
}
- sb.append(s);
+ showErrorMessage(sb.toString());
}
- showErrorMessage(sb.toString());
+ resetDialog();
}
- resetDialog();
+
+ private boolean showError(Throwable e)
+ {
+ String problem = "retrieving " + ids + " from "
+ + database.getSelectedItem();
+ if (e instanceof Exception)
+ {
+ showErrorMessage("Error " + problem);
+ System.err.println("Retrieval failed for source ='"
+ + database.getSelectedItem() + "' and query\n'"
+ + ids + "'\n");
+ }
+ else if (e instanceof OutOfMemoryError)
+ {
+ showErrorMessage("Out of Memory when " + problem
+ + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n");
+ // option here to return false and quit this, but that is not how
+ // original code works - BH
+ // return false;
+ }
+ else
+ {
+ showErrorMessage("Serious Error " + problem);
+ }
+ e.printStackTrace();
+ return true;
+ }
+
}
/**
boolean success = false;
try
{
- if (aresult != null)
- {
- try
- {
- // give the server a chance to breathe
- Thread.sleep(5);
- } catch (Exception e)
- {
- //
- }
- }
-
+ // BH no longer necessary; we are doing 5-ms asynchronous delays all along
+ // if (aresult != null)
+ // {
+ // try
+ // {
+ // // give the server a chance to breathe
+ // Thread.sleep(5);
+ // } catch (Exception e)
+ // {
+ // //
+ // }
+ // }
+ //
AlignmentI indres = null;
try
{
for (String q : queries)
{
- // BH 2019.01.25 dbr is never used.
-// DBRefEntry dbr = new DBRefEntry();
-// dbr.setSource(proxy.getDbSource());
-// dbr.setVersion(null);
+ // BH 2019.01.25 dbr is never used.
+ // DBRefEntry dbr = new DBRefEntry();
+ // dbr.setSource(proxy.getDbSource());
+ // dbr.setVersion(null);
String accId = proxy.getAccessionIdFromQuery(q);
-// dbr.setAccessionId(accId);
+ // dbr.setAccessionId(accId);
boolean rfound = false;
for (int r = 0, nr = rs.length; r < nr; r++)
{
@Override
public void run()
{
- JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), error,
+ JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
+ error,
MessageManager.getString("label.error_retrieving_data"),
JvOptionPane.WARNING_MESSAGE);
}
frame.setVisible(false);
}
- public void setQuery(String ids)
- {
- textArea.setText(ids);
- }
-
/**
* Called to modify the search panel for embedding as an alternative tab of a
* free text search panel. The database choice list is hidden (since the
backBtn.setVisible(true);
parentSearchPanel = parentPanel;
}
+
}