jalview das registry and source api and jdas specific implementations
authorjprocter <jprocter@compbio.dundee.ac.uk>
Wed, 29 Feb 2012 16:00:08 +0000 (16:00 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Wed, 29 Feb 2012 16:00:08 +0000 (16:00 +0000)
src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java [new file with mode: 0644]
src/jalview/ws/dbsources/das/api/jalviewSourceI.java [new file with mode: 0644]
src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java [new file with mode: 0644]
src/jalview/ws/dbsources/das/datamodel/JalviewSource.java [new file with mode: 0644]

diff --git a/src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java b/src/jalview/ws/dbsources/das/api/DasSourceRegistryI.java
new file mode 100644 (file)
index 0000000..187f436
--- /dev/null
@@ -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<jalviewSourceI> 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<jalviewSourceI> resolveSourceNicknames(List<String> sources);
+  // TODO: refactor to jDAS specific interface
+  Map<String,ConnectionPropertyProviderI> 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 (file)
index 0000000..fef6a0b
--- /dev/null
@@ -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<DbSourceProxy> 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 (file)
index 0000000..b17f7f2
--- /dev/null
@@ -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<jalviewSourceI> dasSources = null;
+
+  private Hashtable<String, jalviewSourceI> sourceNames = null;
+
+  private Hashtable<String, jalviewSourceI> 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<jalviewSourceI> getDASSources()
+  {
+
+    return getDASSources(getDasRegistryURL());
+  }
+
+  /**
+   * query the given URL for DasSources.
+   * 
+   * @param registryURL
+   *          return sources from registryURL
+   */
+  private static List<jalviewSourceI> 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<SOURCE> dassources = sources.getSOURCE();
+      ArrayList<jalviewSourceI> dsrc = new ArrayList<jalviewSourceI>();
+      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<jalviewSourceI>();
+    }
+  }
+
+
+  public void run()
+  {
+    getSources();
+  }
+
+  @Override
+  public List<jalviewSourceI> 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<jalviewSourceI> appendLocalSources()
+  {
+    List<jalviewSourceI> srclist=new ArrayList<jalviewSourceI>();
+    addLocalDasSources();
+    sourceNames = new Hashtable<String, jalviewSourceI>();
+    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<String, jalviewSourceI>();
+    }
+    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>());
+    VERSION v = new VERSION();
+    List<CAPABILITY> cp = new ArrayList<CAPABILITY>();
+    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<jalviewSourceI> resolveSourceNicknames(List<String> sources)
+  {
+    ArrayList<jalviewSourceI> resolved = new ArrayList<jalviewSourceI>();
+    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<URL, String> authStash;
+  static
+  {
+    authStash = new Hashtable<URL, String>();
+
+    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<String, ConnectionPropertyProviderI> 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<String, ConnectionPropertyProviderI>()
+    {
+
+      @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<java.util.Map.Entry<String, ConnectionPropertyProviderI>> 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<String> 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<? extends String, ? extends ConnectionPropertyProviderI> 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<ConnectionPropertyProviderI> 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 (file)
index 0000000..a58bf09
--- /dev/null
@@ -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<String> labels = new ArrayList<String>();
+    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<String> labels = new ArrayList<String>();
+    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<DbSourceProxy> getSequenceSourceProxies()
+  {
+    if (!isSequenceSource())
+    {
+      return null;
+    }
+    ArrayList<DbSourceProxy> seqsources = new ArrayList<DbSourceProxy>();
+    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;
+  }
+}