/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.ws.seqfetcher;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.SequenceI;
import jalview.util.DBRefUtils;
import jalview.util.MessageManager;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;
public class ASequenceFetcher
{
/**
* set of databases we can retrieve entries from
*/
protected Hashtable> FETCHABLEDBS;
public ASequenceFetcher()
{
super();
}
/**
* get list of supported Databases
*
* @return database source string for each database - only the latest version
* of a source db is bound to each source.
*/
public String[] getSupportedDb()
{
if (FETCHABLEDBS == null)
{
return null;
}
String[] sf = new String[FETCHABLEDBS.size()];
Enumeration e = FETCHABLEDBS.keys();
int i = 0;
while (e.hasMoreElements())
{
sf[i++] = (String) e.nextElement();
}
;
return sf;
}
public boolean isFetchable(String source)
{
Enumeration e = FETCHABLEDBS.keys();
while (e.hasMoreElements())
{
String db = (String) e.nextElement();
if (source.compareToIgnoreCase(db) == 0)
{
return true;
}
}
jalview.bin.Cache.log.warn("isFetchable doesn't know about '" + source
+ "'");
return false;
}
public SequenceI[] getSequences(jalview.datamodel.DBRefEntry[] refs)
{
SequenceI[] ret = null;
Vector rseqs = new Vector();
Hashtable> queries = new Hashtable();
for (int r = 0; r < refs.length; r++)
{
if (!queries.containsKey(refs[r].getSource()))
{
queries.put(refs[r].getSource(), new ArrayList());
}
List qset = queries.get(refs[r].getSource());
if (!qset.contains(refs[r].getAccessionId()))
{
qset.add(refs[r].getAccessionId());
}
}
Enumeration e = queries.keys();
while (e.hasMoreElements())
{
List query = null;
String db = null;
db = e.nextElement();
query = queries.get(db);
if (!isFetchable(db))
{
reportStdError(db, query, new Exception(
"Don't know how to fetch from this database :" + db));
continue;
}
Iterator fetchers = getSourceProxy(db).iterator();
Stack queriesLeft = new Stack();
// List queriesFailed = new ArrayList();
queriesLeft.addAll(query);
while (fetchers.hasNext())
{
List queriesMade = new ArrayList();
HashSet queriesFound = new HashSet();
try
{
DbSourceProxy fetcher = fetchers.next();
boolean doMultiple = fetcher.getAccessionSeparator() != null; // No
// separator
// - no
// Multiple
// Queries
while (!queriesLeft.isEmpty())
{
StringBuffer qsb = new StringBuffer();
do
{
if (qsb.length() > 0)
{
qsb.append(fetcher.getAccessionSeparator());
}
String q = queriesLeft.pop();
queriesMade.add(q);
qsb.append(q);
} while (doMultiple && !queriesLeft.isEmpty());
AlignmentI seqset = null;
try
{
// create a fetcher and go to it
seqset = fetcher.getSequenceRecords(qsb.toString()); // ,
// queriesFailed);
} catch (Exception ex)
{
System.err.println("Failed to retrieve the following from "
+ db);
System.err.println(qsb);
ex.printStackTrace(System.err);
}
// TODO: Merge alignment together - perhaps
if (seqset != null)
{
SequenceI seqs[] = seqset.getSequencesArray();
if (seqs != null)
{
for (int is = 0; is < seqs.length; is++)
{
rseqs.addElement(seqs[is]);
DBRefEntry[] frefs = DBRefUtils.searchRefs(seqs[is]
.getDBRefs(), new DBRefEntry(db, null, null));
if (frefs != null)
{
for (DBRefEntry dbr : frefs)
{
queriesFound.add(dbr.getAccessionId());
queriesMade.remove(dbr.getAccessionId());
}
}
seqs[is] = null;
}
}
else
{
if (fetcher.getRawRecords() != null)
{
System.out.println("# Retrieved from " + db + ":"
+ qsb.toString());
StringBuffer rrb = fetcher.getRawRecords();
/*
* for (int rr = 0; rr 0)
{
System.out.println("# Adding " + queriesMade.size()
+ " ids back to queries list for searching again (" + db
+ ".");
queriesLeft.addAll(queriesMade);
}
}
}
if (rseqs.size() > 0)
{
ret = new SequenceI[rseqs.size()];
Enumeration sqs = rseqs.elements();
int si = 0;
while (sqs.hasMoreElements())
{
SequenceI s = (SequenceI) sqs.nextElement();
ret[si++] = s;
s.updatePDBIds();
}
}
return ret;
}
public void reportStdError(String db, List queriesMade,
Exception ex)
{
System.err.println("Failed to retrieve the following references from "
+ db);
int n = 0;
for (String qv : queriesMade)
{
System.err.print(" " + qv + ";");
if (n++ > 10)
{
System.err.println();
n = 0;
}
}
System.err.println();
ex.printStackTrace();
}
/**
* Retrieve an instance of the proxy for the given source
*
* @param db
* database source string TODO: add version string/wildcard for
* retrieval of specific DB source/version combinations.
* @return an instance of DbSourceProxy for that db.
*/
public List getSourceProxy(String db)
{
List dbs;
Map dblist = FETCHABLEDBS.get(db);
if (dblist == null)
{
return new ArrayList();
}
;
if (dblist.size() > 1)
{
DbSourceProxy[] l = dblist.values().toArray(new DbSourceProxy[0]);
int i = 0;
String[] nm = new String[l.length];
// make sure standard dbs appear first, followed by reference das sources,
// followed by anything else.
for (DbSourceProxy s : l)
{
nm[i++] = "" + s.getTier() + s.getDbName().toLowerCase();
}
jalview.util.QuickSort.sort(nm, l);
dbs = new ArrayList();
for (i = l.length - 1; i >= 0; i--)
{
dbs.add(l[i]);
}
}
else
{
dbs = new ArrayList(dblist.values());
}
return dbs;
}
/**
* constructs and instance of the proxy and registers it as a valid
* dbrefsource
*
* @param dbSourceProxy
* reference for class implementing
* jalview.ws.seqfetcher.DbSourceProxy
*/
protected void addDBRefSourceImpl(
Class extends DbSourceProxy> dbSourceProxy)
throws java.lang.IllegalArgumentException
{
DbSourceProxy proxy = null;
try
{
DbSourceProxy proxyObj = dbSourceProxy.getConstructor().newInstance();
proxy = proxyObj;
} catch (IllegalArgumentException e)
{
throw e;
} catch (Exception e)
{
// Serious problems if this happens.
throw new Error(
MessageManager
.getString("error.dbrefsource_implementation_exception"),
e);
}
addDbRefSourceImpl(proxy);
}
/**
* add the properly initialised DbSourceProxy object 'proxy' to the list of
* sequence fetchers
*
* @param proxy
*/
protected void addDbRefSourceImpl(DbSourceProxy proxy)
{
if (proxy != null)
{
if (FETCHABLEDBS == null)
{
FETCHABLEDBS = new Hashtable>();
}
Map slist = FETCHABLEDBS.get(proxy
.getDbSource());
if (slist == null)
{
FETCHABLEDBS.put(proxy.getDbSource(),
slist = new Hashtable());
}
slist.put(proxy.getDbName(), proxy);
}
}
/**
* test if the database handler for dbName contains the given dbProperty when
* a dbName resolves to a set of proxies - this method will return the result
* of the test for the first instance. TODO implement additional method to
* query all sources for a db to find one with a particular property
*
* @param dbName
* @param dbProperty
* @return true if proxy has the given property
*/
public boolean hasDbSourceProperty(String dbName, String dbProperty)
{
// TODO: decide if invalidDbName exception is thrown here.
List proxies = getSourceProxy(dbName);
if (proxies != null)
{
for (DbSourceProxy proxy : proxies)
{
if (proxy.getDbSourceProperties() != null)
{
return proxy.getDbSourceProperties().containsKey(dbProperty);
}
}
}
return false;
}
/**
* select sources which are implemented by instances of the given class
*
* @param class that implements DbSourceProxy
* @return null or vector of source names for fetchers
*/
public String[] getDbInstances(Class class1)
{
if (!jalview.ws.seqfetcher.DbSourceProxy.class.isAssignableFrom(class1))
{
throw new Error(
MessageManager
.formatMessage(
"error.implementation_error_dbinstance_must_implement_interface",
new String[] { class1.toString() }));
}
if (FETCHABLEDBS == null)
{
return null;
}
String[] sources = null;
Vector src = new Vector();
Enumeration dbs = FETCHABLEDBS.keys();
while (dbs.hasMoreElements())
{
String dbn = (String) dbs.nextElement();
for (DbSourceProxy dbp : FETCHABLEDBS.get(dbn).values())
{
if (class1.isAssignableFrom(dbp.getClass()))
{
src.addElement(dbn);
}
}
}
if (src.size() > 0)
{
src.copyInto(sources = new String[src.size()]);
}
return sources;
}
public DbSourceProxy[] getDbSourceProxyInstances(Class class1)
{
ArrayList prlist = new ArrayList();
for (String fetchable : getSupportedDb())
{
for (DbSourceProxy pr : getSourceProxy(fetchable))
{
if (class1.isInstance(pr))
{
prlist.add(pr);
}
}
}
if (prlist.size() == 0)
{
return null;
}
return prlist.toArray(new DbSourceProxy[0]);
}
}