From 339ed5130c391c6028e01222e8ba293b8209b524 Mon Sep 17 00:00:00 2001 From: jprocter Date: Wed, 29 Feb 2012 16:00:08 +0000 Subject: [PATCH] jalview das registry and source api and jdas specific implementations --- .../ws/dbsources/das/api/DasSourceRegistryI.java | 35 ++ .../ws/dbsources/das/api/jalviewSourceI.java | 49 ++ .../dbsources/das/datamodel/DasSourceRegistry.java | 491 ++++++++++++++++++++ .../ws/dbsources/das/datamodel/JalviewSource.java | 266 +++++++++++ 4 files changed, 841 insertions(+) create mode 100644 src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java create mode 100644 src/jalview/ws/dbsources/das/api/jalviewSourceI.java create mode 100644 src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java create mode 100644 src/jalview/ws/dbsources/das/datamodel/JalviewSource.java diff --git a/src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java b/src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java new file mode 100644 index 0000000..187f436 --- /dev/null +++ b/src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java @@ -0,0 +1,35 @@ +package jalview.ws.dbsources.das.api; + +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import org.biodas.jdas.client.ConnectionPropertyProviderI; +import org.biodas.jdas.schema.sources.SOURCE; + +/** + * API for a registry that provides datasources that jalview can access + * @author jprocter + * + */ +public interface DasSourceRegistryI +{ + + List getSources(); + + String getDasRegistryURL(); + + jalviewSourceI getSource(String nickname); + + jalviewSourceI createLocalSource(String uri, String name, boolean sequence, + boolean features); + boolean removeLocalSource(jalviewSourceI source); + + void refreshSources(); + + String getLocalSourceString(); + + List resolveSourceNicknames(List sources); + // TODO: refactor to jDAS specific interface + Map getSessionHandler(); +} diff --git a/src/jalview/ws/dbsources/das/api/jalviewSourceI.java b/src/jalview/ws/dbsources/das/api/jalviewSourceI.java new file mode 100644 index 0000000..fef6a0b --- /dev/null +++ b/src/jalview/ws/dbsources/das/api/jalviewSourceI.java @@ -0,0 +1,49 @@ +package jalview.ws.dbsources.das.api; + +import java.util.List; + +import jalview.ws.seqfetcher.DbSourceProxy; + +import org.biodas.jdas.schema.sources.MAINTAINER; +import org.biodas.jdas.schema.sources.VERSION; + +public interface jalviewSourceI +{ + + String getTitle(); + + VERSION getVersion(); + + String getDocHref(); + + String getDescription(); + + String getUri(); + + MAINTAINER getMAINTAINER(); + + String getEmail(); + + boolean isLocal(); + + boolean isSequenceSource(); + + String[] getCapabilityList(VERSION v); + + String[] getLabelsFor(VERSION v); + + /** + * + * @return null if not a sequence source, otherwise a series of database sources that can be used to retrieve sequence data for particular database coordinate systems + */ + List getSequenceSourceProxies(); + + boolean isFeatureSource(); + + /** + * returns the base URL for the latest version of a source's DAS endpoint set + * @return + */ + String getSourceURL(); + +} diff --git a/src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java b/src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java new file mode 100644 index 0000000..b17f7f2 --- /dev/null +++ b/src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java @@ -0,0 +1,491 @@ +/** + * + */ +package jalview.ws.dbsources.das.datamodel; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.swing.JOptionPane; + +import org.apache.http.auth.InvalidCredentialsException; +import org.biodas.jdas.client.ConnectionPropertyProviderI; +import org.biodas.jdas.client.SourcesClient; +import org.biodas.jdas.dassources.Capabilities; +import org.biodas.jdas.schema.sources.CAPABILITY; +import org.biodas.jdas.schema.sources.SOURCE; +import org.biodas.jdas.schema.sources.SOURCES; +import org.biodas.jdas.schema.sources.VERSION; + +import jalview.bin.Cache; +import jalview.ws.dbsources.das.api.DasSourceRegistryI; +import jalview.ws.dbsources.das.api.jalviewSourceI; + +/** + * + */ +public class DasSourceRegistry implements DasSourceRegistryI +{ + // private org.biodas.jdas.schema.sources.SOURCE[] dasSources = null; + private List dasSources = null; + + private Hashtable sourceNames = null; + + private Hashtable localSources = null; + + public static String DEFAULT_REGISTRY = "http://www.dasregistry.org/das1/sources/"; + + /** + * true if thread is running and we are talking to DAS registry service + */ + private boolean loadingDasSources = false; + + public boolean isLoadingDasSources() + { + return loadingDasSources; + } + + public String getDasRegistryURL() + { + String registry = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL", + DEFAULT_REGISTRY); + + if (registry.indexOf("/registry/das1/sources/") > -1) + { + jalview.bin.Cache.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL, + DEFAULT_REGISTRY); + registry = DEFAULT_REGISTRY; + } + return registry; + } + + /** + * query the default DAS Source Registry for sources. Uses value of jalview + * property DAS_REGISTRY_URL and the DasSourceBrowser.DEFAULT_REGISTRY if that + * doesn't exist. + * + * @return list of sources + */ + private List getDASSources() + { + + return getDASSources(getDasRegistryURL()); + } + + /** + * query the given URL for DasSources. + * + * @param registryURL + * return sources from registryURL + */ + private static List getDASSources(String registryURL) + { + try + { + URL url = new URL(registryURL); + org.biodas.jdas.client.SourcesClientInterface client = new SourcesClient(); + + SOURCES sources = client.fetchDataRegistry(registryURL, null, null, null, null, null, null); + + List dassources = sources.getSOURCE(); + ArrayList dsrc = new ArrayList(); + for (SOURCE src : dassources) + { + dsrc.add(new JalviewSource(src, false)); + } + return dsrc; + } catch (Exception ex) + { + System.err.println("Failed to contact DAS1 registry at " + + registryURL); + ex.printStackTrace(); + return new ArrayList(); + } + } + + + public void run() + { + getSources(); + } + + @Override + public List getSources() + { + if (dasSources == null) + { + dasSources = getDASSources(); + } + return appendLocalSources(); + } + + /** + * generate Sources from the local das source list + * + */ + private void addLocalDasSources() + { + String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE"); + if (local != null) + { + StringTokenizer st = new StringTokenizer(local, "\t"); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + int bar = token.indexOf("|"); + String url = token.substring(bar + 1); + boolean features = true, sequence = false; + if (url.startsWith("sequence:")) + { + url = url.substring(9); + // this source also serves sequences as well as features + sequence = true; + } + createLocalSource(url, token.substring(0, bar), sequence, features); + } + } + } + + private List appendLocalSources() + { + List srclist=new ArrayList(); + addLocalDasSources(); + sourceNames = new Hashtable(); + if (dasSources != null) + { + for (jalviewSourceI src : dasSources) + { + sourceNames.put(src.getTitle(), src); + srclist.add(src); + } + } + + if (localSources == null) + { + return srclist; + } + Enumeration en = localSources.keys(); + while (en.hasMoreElements()) + { + String key = en.nextElement().toString(); + jalviewSourceI jvsrc = localSources.get(key); + sourceNames.put(key, jvsrc); + srclist.add(jvsrc); + } + return srclist; + } + + /* + * + */ + + @Override + public jalviewSourceI createLocalSource(String url, String name, + boolean sequence, boolean features) + { + SOURCE local = _createLocalSource(url, name, sequence, features); + + if (localSources == null) + { + localSources = new Hashtable(); + } + jalviewSourceI src=new JalviewSource(local, true); + localSources.put(local.getTitle(), src); + return src; + } + + private SOURCE _createLocalSource(String url, String name, + boolean sequence, boolean features) + { + SOURCE local = new SOURCE(); + + local.setUri(url); + local.setTitle(name); + local.setVERSION(new ArrayList()); + VERSION v = new VERSION(); + List cp = new ArrayList(); + if (sequence) + { + /* + * Could try and synthesize a coordinate system for the source if needbe + * COORDINATES coord = new COORDINATES(); coord.setAuthority("NCBI"); + * coord.setSource("Chromosome"); coord.setTaxid("9606"); + * coord.setVersion("35"); version.getCOORDINATES().add(coord); + */ + CAPABILITY cap = new CAPABILITY(); + cap.setType("das1:" + Capabilities.SEQUENCE.getName()); + cap.setQueryUri(url+"/sequence"); + cp.add(cap); + } + if (features) + { + CAPABILITY cap = new CAPABILITY(); + cap.setType("das1:" + Capabilities.FEATURES.getName()); + cap.setQueryUri(url+"/features"); + cp.add(cap); + } + + v.getCAPABILITY().addAll(cp); + local.getVERSION().add(v); + + return local; + } + + @Override + public jalviewSourceI getSource(String nickname) + { + return sourceNames.get(nickname); + } + + @Override + public boolean removeLocalSource(jalviewSourceI source) + { + if (localSources.containsValue(source)) + { + localSources.remove(source.getTitle()); + sourceNames.remove(source.getTitle()); + dasSources.remove(source); + return true; + } + return false; + } + + @Override + public void refreshSources() + { + dasSources = null; + sourceNames = null; + run(); + } + + @Override + public List resolveSourceNicknames(List sources) + { + ArrayList resolved = new ArrayList(); + if (sourceNames != null) + { + for (String src : sources) + { + jalviewSourceI dsrc = sourceNames.get(src); + if (dsrc != null) + { + resolved.add(dsrc); + } + } + } + return resolved; + } + + @Override + public String getLocalSourceString() + { + if (localSources != null) + { + StringBuffer sb = new StringBuffer(); + Enumeration en = localSources.keys(); + while (en.hasMoreElements()) + { + String token = en.nextElement().toString(); + jalviewSourceI srco = localSources.get(token); + sb.append(token + "|" + + (srco.isSequenceSource() ? "sequence:" : "") + + srco.getUri() + "\t"); + } + return sb.toString(); + } + return ""; + } + + private static final Hashtable authStash; + static + { + authStash = new Hashtable(); + + try + { + // TODO: allow same credentials for https and http + authStash.put(new URL( + "http://www.compbio.dundee.ac.uk/geneweb/das/myseq/"), + "Basic SmltOm1pSg=="); + } catch (MalformedURLException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public Map getSessionHandler() + { + final ConnectionPropertyProviderI conprov = new ConnectionPropertyProviderI() + { + boolean authed = false; + + @Override + public void setConnectionProperties(HttpURLConnection connection) + { + String auth = authStash.get(connection.getURL()); + if (auth != null && auth.length() > 0) + { + connection.setRequestProperty("Authorisation", auth); + authed = true; + } + else + { + authed = false; + } + } + + @Override + public boolean getResponseProperties(HttpURLConnection connection) + { + String auth = authStash.get(connection.getURL()); + if (auth != null && auth.length() == 0) + { + // don't attempt to check if we authed or not - user entered empty + // password + return false; + } + if (!authed) + { + if (auth != null) + { + // try and pass credentials. + return true; + } + // see if we should try and create a new auth record. + String ameth = connection.getHeaderField("X-DAS-AuthMethods"); + Cache.log.debug("Could authenticate to " + connection.getURL() + + " with : " + ameth); + // TODO: search auth string and raise login box - return if auth was + // provided + return false; + } + else + { + // check to see if auth was successful + String asuc = connection + .getHeaderField("X-DAS_AuthenticatedUser"); + if (asuc != null && asuc.trim().length() > 0) + { + // authentication was successful + Cache.log.debug("Authenticated successfully as " + asuc + + " with " + connection.getURL().toString()); + return false; + } + // it wasn't - so we should tell the user it failed and ask if they + // want to attempt authentication again. + authStash.remove(connection.getURL()); + // open a new login/password dialog with cancel button + // set new authStash content with password and return true + return true; // + // User cancelled auth - so put empty string in stash to indicate we + // don't want to auth with this server. + // authStash.put(connection.getURL(), ""); + // return false; + } + } + }; + return new Map() + { + + @Override + public void clear() + { + // TODO Auto-generated method stub + + } + + @Override + public boolean containsKey(Object key) + { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean containsValue(Object value) + { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set> entrySet() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConnectionPropertyProviderI get(Object key) + { + return conprov; + } + + @Override + public boolean isEmpty() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set keySet() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConnectionPropertyProviderI put(String key, + ConnectionPropertyProviderI value) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void putAll( + Map m) + { + // TODO Auto-generated method stub + + } + + @Override + public ConnectionPropertyProviderI remove(Object key) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public int size() + { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Collection values() + { + // TODO Auto-generated method stub + return null; + } + + }; + } + +} diff --git a/src/jalview/ws/dbsources/das/datamodel/JalviewSource.java b/src/jalview/ws/dbsources/das/datamodel/JalviewSource.java new file mode 100644 index 0000000..a58bf09 --- /dev/null +++ b/src/jalview/ws/dbsources/das/datamodel/JalviewSource.java @@ -0,0 +1,266 @@ +package jalview.ws.dbsources.das.datamodel; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.biodas.jdas.dassources.Capabilities; +import org.biodas.jdas.dassources.utils.DasTimeFormat; +import org.biodas.jdas.dassources.utils.RegistrySourceAdapter; +import org.biodas.jdas.schema.sources.CAPABILITY; +import org.biodas.jdas.schema.sources.COORDINATES; +import org.biodas.jdas.schema.sources.MAINTAINER; +import org.biodas.jdas.schema.sources.PROP; +import org.biodas.jdas.schema.sources.SOURCE; +import org.biodas.jdas.schema.sources.VERSION; + +import sun.plugin2.message.GetNameSpaceMessage; + +import jalview.ws.dbsources.DasSequenceSource; +import jalview.ws.dbsources.das.api.jalviewSourceI; +import jalview.ws.seqfetcher.DbSourceProxy; + +public class JalviewSource implements jalviewSourceI +{ + SOURCE source; + + public JalviewSource(SOURCE local2, boolean local) + { + this.local = local; + source = local2; + } + + @Override + public String getTitle() + { + return source.getTitle(); + } + + @Override + public VERSION getVersion() + { + + return getVersionFor(source); + } + + @Override + public String getDocHref() + { + return source.getDocHref(); + } + + @Override + public String getDescription() + { + return source.getDescription(); + } + + @Override + public String getUri() + { + return source.getUri(); + } + + @Override + public MAINTAINER getMAINTAINER() + { + return source.getMAINTAINER(); + } + + @Override + public String getEmail() + { + return (local) ? null: source.getMAINTAINER().getEmail(); + } + + boolean local = false; + + @Override + public boolean isLocal() + { + return local; + } + + @Override + public boolean isSequenceSource() + { + String seqcap = "das1:" + Capabilities.SEQUENCE.getName(); + for (String cp : getCapabilityList(getVersionFor(source))) + { + if (cp.equals(seqcap)) + { + return true; + + } + } + return false; + } + @Override + public boolean isFeatureSource() + { + String seqcap = "das1:" + Capabilities.FEATURES.getName(); + for (String cp : getCapabilityList(getVersionFor(source))) + { + if (cp.equals(seqcap)) + { + return true; + + } + } + return false; + } + + private VERSION getVersionFor(SOURCE ds) + { + VERSION latest = null; + for (VERSION v : ds.getVERSION()) + { + if (latest == null + || isLaterThan(latest.getCreated(), v.getCreated())) + { + // TODO: das 1.6 - should just get the first version - ignore other + // versions since not specified how to construct URL from version's URI + // + source URI + latest = v; + } + } + return latest; + } + + private boolean isLaterThan(String ref, String newer) + { + Date refdate = null, newdate = null; + try + { + refdate = DasTimeFormat.fromDASString(ref); + + } catch (ParseException x) + { + return false; + } + try + { + newdate = DasTimeFormat.fromDASString(newer); + } catch (ParseException e) + { + // TODO: handle exception + } + if (refdate != null) + { + if (newdate != null) + { + return refdate.before(newdate); + } + return false; + } + if (newdate != null) + { + return true; + } + // assume first instance of source is newest in list. - TODO: check if + // natural ordering of source versions is newest first or oldest first + return false; + } + + public String[] getLabelsFor(VERSION v) + { + ArrayList labels = new ArrayList(); + for (PROP p : v.getPROP()) + { + if (p.getName().equalsIgnoreCase("LABEL")) + { + labels.add(p.getValue()); + } + } + return labels.toArray(new String[0]); + } + + private CAPABILITY getCapability(Capabilities capability) { + for (CAPABILITY p: getVersion().getCAPABILITY()) { + if (p.getType().equalsIgnoreCase(capability.getName()) || p.getType().equalsIgnoreCase("das1:"+capability.getName())) + { + return p; + } + } + return null; + } + public String[] getCapabilityList(VERSION v) + { + + ArrayList labels = new ArrayList(); + for (CAPABILITY p : v.getCAPABILITY()) + { + // TODO: work out what to do with namespace prefix + // does SEQUENCE == das1:SEQUENCE and das2:SEQUENCE ? + // for moment, just show all capabilities... + if (p.getType().startsWith("das1:")) + { + labels.add(p.getType()); + } + } + return labels.toArray(new String[0]); + } + + @Override + public List getSequenceSourceProxies() + { + if (!isSequenceSource()) + { + return null; + } + ArrayList seqsources = new ArrayList(); + if (!local) + { + VERSION v = getVersion(); + for (COORDINATES cs : v.getCOORDINATES()) + { + + /* + * if (css == null || css.length == 0) { // TODO: query das source + * directly to identify coordinate system... or // have to make up a + * coordinate system css = new DasCoordinateSystem[] { new + * DasCoordinateSystem() }; css[0].setName(d1s.getNickname()); + * css[0].setUniqueId(d1s.getNickname()); } for (int c = 0; c < + * css.length; c++) { + */ + try + { + seqsources.add(new DasSequenceSource("das:" + getTitle() + " (" + + cs.getContent() + ")", cs.getContent(), source, v, cs)); + } catch (Exception e) + { + System.err.println("Ignoring sequence coord system " + cs + " (" + + cs.getContent() + ") for source " + getTitle() + + "- threw exception when constructing fetcher.\n"); + e.printStackTrace(); + } + } + } else { + try + { + seqsources.add(new DasSequenceSource("das:"+getTitle(), getTitle(), source, getVersion(), null)); + } catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return seqsources; + } + @Override + public String getSourceURL() + { + try { + String url = new RegistrySourceAdapter(source).getOriginalDataSourceUri(); + return url; + } + catch (Exception x) + { + System.err.println("Serious: Couldn't get the URL for source "+source.getTitle()); + x.printStackTrace(); + } + return null; + } +} -- 1.7.10.2