jalview das registry and source api and jdas specific implementations
[jalview.git] / src / jalview / ws / dbsources / das / datamodel / DasSourceRegistry.java
1 /**
2  * 
3  */
4 package jalview.ws.dbsources.das.datamodel;
5
6 import java.net.HttpURLConnection;
7 import java.net.MalformedURLException;
8 import java.net.URL;
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.Enumeration;
12 import java.util.HashMap;
13 import java.util.Hashtable;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.StringTokenizer;
18 import java.util.Vector;
19
20 import javax.swing.JOptionPane;
21
22 import org.apache.http.auth.InvalidCredentialsException;
23 import org.biodas.jdas.client.ConnectionPropertyProviderI;
24 import org.biodas.jdas.client.SourcesClient;
25 import org.biodas.jdas.dassources.Capabilities;
26 import org.biodas.jdas.schema.sources.CAPABILITY;
27 import org.biodas.jdas.schema.sources.SOURCE;
28 import org.biodas.jdas.schema.sources.SOURCES;
29 import org.biodas.jdas.schema.sources.VERSION;
30
31 import jalview.bin.Cache;
32 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
33 import jalview.ws.dbsources.das.api.jalviewSourceI;
34
35 /**
36  *
37  */
38 public class DasSourceRegistry implements DasSourceRegistryI
39 {
40   // private org.biodas.jdas.schema.sources.SOURCE[] dasSources = null;
41   private List<jalviewSourceI> dasSources = null;
42
43   private Hashtable<String, jalviewSourceI> sourceNames = null;
44
45   private Hashtable<String, jalviewSourceI> localSources = null;
46
47   public static String DEFAULT_REGISTRY = "http://www.dasregistry.org/das1/sources/";
48
49   /**
50    * true if thread is running and we are talking to DAS registry service
51    */
52   private boolean loadingDasSources = false;
53
54   public boolean isLoadingDasSources()
55   {
56     return loadingDasSources;
57   }
58
59   public String getDasRegistryURL()
60   {
61     String registry = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",
62             DEFAULT_REGISTRY);
63
64     if (registry.indexOf("/registry/das1/sources/") > -1)
65     {
66       jalview.bin.Cache.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,
67               DEFAULT_REGISTRY);
68       registry = DEFAULT_REGISTRY;
69     }
70     return registry;
71   }
72
73   /**
74    * query the default DAS Source Registry for sources. Uses value of jalview
75    * property DAS_REGISTRY_URL and the DasSourceBrowser.DEFAULT_REGISTRY if that
76    * doesn't exist.
77    * 
78    * @return list of sources
79    */
80   private List<jalviewSourceI> getDASSources()
81   {
82
83     return getDASSources(getDasRegistryURL());
84   }
85
86   /**
87    * query the given URL for DasSources.
88    * 
89    * @param registryURL
90    *          return sources from registryURL
91    */
92   private static List<jalviewSourceI> getDASSources(String registryURL)
93   {
94     try
95     {
96       URL url = new URL(registryURL);
97       org.biodas.jdas.client.SourcesClientInterface client = new SourcesClient();
98
99       SOURCES sources = client.fetchDataRegistry(registryURL, null, null, null, null, null, null);
100
101       List<SOURCE> dassources = sources.getSOURCE();
102       ArrayList<jalviewSourceI> dsrc = new ArrayList<jalviewSourceI>();
103       for (SOURCE src : dassources)
104       {
105         dsrc.add(new JalviewSource(src, false));
106       }
107       return dsrc;
108     } catch (Exception ex)
109     {
110       System.err.println("Failed to contact DAS1 registry at "
111               + registryURL);
112       ex.printStackTrace();
113       return new ArrayList<jalviewSourceI>();
114     }
115   }
116
117
118   public void run()
119   {
120     getSources();
121   }
122
123   @Override
124   public List<jalviewSourceI> getSources()
125   {
126     if (dasSources == null)
127     {
128       dasSources = getDASSources();
129     }
130     return appendLocalSources();
131   }
132
133   /**
134    * generate Sources from the local das source list
135    * 
136    */
137   private void addLocalDasSources()
138   {
139     String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE");
140     if (local != null)
141     {
142       StringTokenizer st = new StringTokenizer(local, "\t");
143       while (st.hasMoreTokens())
144       {
145         String token = st.nextToken();
146         int bar = token.indexOf("|");
147         String url = token.substring(bar + 1);
148         boolean features = true, sequence = false;
149         if (url.startsWith("sequence:"))
150         {
151           url = url.substring(9);
152           // this source also serves sequences as well as features
153           sequence = true;
154         }
155         createLocalSource(url, token.substring(0, bar), sequence, features);
156       }
157     }
158   }
159
160   private List<jalviewSourceI> appendLocalSources()
161   {
162     List<jalviewSourceI> srclist=new ArrayList<jalviewSourceI>();
163     addLocalDasSources();
164     sourceNames = new Hashtable<String, jalviewSourceI>();
165     if (dasSources != null)
166     {
167       for (jalviewSourceI src : dasSources)
168       {
169         sourceNames.put(src.getTitle(), src);
170         srclist.add(src);
171       }
172     }
173
174     if (localSources == null)
175     {
176       return srclist;
177     }
178     Enumeration en = localSources.keys();
179     while (en.hasMoreElements())
180     {
181       String key = en.nextElement().toString();
182       jalviewSourceI jvsrc = localSources.get(key);
183       sourceNames.put(key, jvsrc);
184       srclist.add(jvsrc);
185     }
186     return srclist;
187   }
188
189   /*
190  * 
191  */
192
193   @Override
194   public jalviewSourceI createLocalSource(String url, String name,
195           boolean sequence, boolean features)
196   {
197     SOURCE local = _createLocalSource(url, name, sequence, features);
198
199     if (localSources == null)
200     {
201       localSources = new Hashtable<String, jalviewSourceI>();
202     }
203     jalviewSourceI src=new JalviewSource(local, true);
204     localSources.put(local.getTitle(), src);
205     return src;
206   }
207
208   private SOURCE _createLocalSource(String url, String name,
209           boolean sequence, boolean features)
210   {
211     SOURCE local = new SOURCE();
212
213     local.setUri(url);
214     local.setTitle(name);
215     local.setVERSION(new ArrayList<VERSION>());
216     VERSION v = new VERSION();
217     List<CAPABILITY> cp = new ArrayList<CAPABILITY>();
218     if (sequence)
219     {
220       /*
221        * Could try and synthesize a coordinate system for the source if needbe
222        * COORDINATES coord = new COORDINATES(); coord.setAuthority("NCBI");
223        * coord.setSource("Chromosome"); coord.setTaxid("9606");
224        * coord.setVersion("35"); version.getCOORDINATES().add(coord);
225        */
226       CAPABILITY cap = new CAPABILITY();
227       cap.setType("das1:" + Capabilities.SEQUENCE.getName());
228       cap.setQueryUri(url+"/sequence");
229       cp.add(cap);
230     }
231     if (features)
232     {
233       CAPABILITY cap = new CAPABILITY();
234       cap.setType("das1:" + Capabilities.FEATURES.getName());
235       cap.setQueryUri(url+"/features");
236       cp.add(cap);
237     }
238
239     v.getCAPABILITY().addAll(cp);
240     local.getVERSION().add(v);
241
242     return local;
243   }
244
245   @Override
246   public jalviewSourceI getSource(String nickname)
247   {
248     return sourceNames.get(nickname);
249   }
250
251   @Override
252   public boolean removeLocalSource(jalviewSourceI source)
253   {
254     if (localSources.containsValue(source))
255     {
256       localSources.remove(source.getTitle());
257       sourceNames.remove(source.getTitle());
258       dasSources.remove(source);
259       return true;
260     }
261     return false;
262   }
263
264   @Override
265   public void refreshSources()
266   {
267     dasSources = null;
268     sourceNames = null;
269     run();
270   }
271
272   @Override
273   public List<jalviewSourceI> resolveSourceNicknames(List<String> sources)
274   {
275     ArrayList<jalviewSourceI> resolved = new ArrayList<jalviewSourceI>();
276     if (sourceNames != null)
277     {
278       for (String src : sources)
279       {
280         jalviewSourceI dsrc = sourceNames.get(src);
281         if (dsrc != null)
282         {
283           resolved.add(dsrc);
284         }
285       }
286     }
287     return resolved;
288   }
289
290   @Override
291   public String getLocalSourceString()
292   {
293     if (localSources != null)
294     {
295       StringBuffer sb = new StringBuffer();
296       Enumeration en = localSources.keys();
297       while (en.hasMoreElements())
298       {
299         String token = en.nextElement().toString();
300         jalviewSourceI srco = localSources.get(token);
301         sb.append(token + "|"
302                 + (srco.isSequenceSource() ? "sequence:" : "")
303                 + srco.getUri() + "\t");
304       }
305       return sb.toString();
306     }
307     return "";
308   }
309
310   private static final Hashtable<URL, String> authStash;
311   static
312   {
313     authStash = new Hashtable<URL, String>();
314
315     try
316     {
317       // TODO: allow same credentials for https and http
318       authStash.put(new URL(
319               "http://www.compbio.dundee.ac.uk/geneweb/das/myseq/"),
320               "Basic SmltOm1pSg==");
321     } catch (MalformedURLException e)
322     {
323       // TODO Auto-generated catch block
324       e.printStackTrace();
325     }
326   }
327
328   @Override
329   public Map<String, ConnectionPropertyProviderI> getSessionHandler()
330   {
331     final ConnectionPropertyProviderI conprov = new ConnectionPropertyProviderI()
332     {
333       boolean authed = false;
334
335       @Override
336       public void setConnectionProperties(HttpURLConnection connection)
337       {
338         String auth = authStash.get(connection.getURL());
339         if (auth != null && auth.length() > 0)
340         {
341           connection.setRequestProperty("Authorisation", auth);
342           authed = true;
343         }
344         else
345         {
346           authed = false;
347         }
348       }
349
350       @Override
351       public boolean getResponseProperties(HttpURLConnection connection)
352       {
353         String auth = authStash.get(connection.getURL());
354         if (auth != null && auth.length() == 0)
355         {
356           // don't attempt to check if we authed or not - user entered empty
357           // password
358           return false;
359         }
360         if (!authed)
361         {
362           if (auth != null)
363           {
364             // try and pass credentials.
365             return true;
366           }
367           // see if we should try and create a new auth record.
368           String ameth = connection.getHeaderField("X-DAS-AuthMethods");
369           Cache.log.debug("Could authenticate to " + connection.getURL()
370                   + " with : " + ameth);
371           // TODO: search auth string and raise login box - return if auth was
372           // provided
373           return false;
374         }
375         else
376         {
377           // check to see if auth was successful
378           String asuc = connection
379                   .getHeaderField("X-DAS_AuthenticatedUser");
380           if (asuc != null && asuc.trim().length() > 0)
381           {
382             // authentication was successful
383             Cache.log.debug("Authenticated successfully as " + asuc
384                     + " with " + connection.getURL().toString());
385             return false;
386           }
387           // it wasn't - so we should tell the user it failed and ask if they
388           // want to attempt authentication again.
389           authStash.remove(connection.getURL());
390           // open a new login/password dialog with cancel button
391           // set new authStash content with password and return true
392           return true; //
393           // User cancelled auth - so put empty string in stash to indicate we
394           // don't want to auth with this server.
395           // authStash.put(connection.getURL(), "");
396           // return false;
397         }
398       }
399     };
400     return new Map<String, ConnectionPropertyProviderI>()
401     {
402
403       @Override
404       public void clear()
405       {
406         // TODO Auto-generated method stub
407
408       }
409
410       @Override
411       public boolean containsKey(Object key)
412       {
413         // TODO Auto-generated method stub
414         return false;
415       }
416
417       @Override
418       public boolean containsValue(Object value)
419       {
420         // TODO Auto-generated method stub
421         return false;
422       }
423
424       @Override
425       public Set<java.util.Map.Entry<String, ConnectionPropertyProviderI>> entrySet()
426       {
427         // TODO Auto-generated method stub
428         return null;
429       }
430
431       @Override
432       public ConnectionPropertyProviderI get(Object key)
433       {
434         return conprov;
435       }
436
437       @Override
438       public boolean isEmpty()
439       {
440         // TODO Auto-generated method stub
441         return false;
442       }
443
444       @Override
445       public Set<String> keySet()
446       {
447         // TODO Auto-generated method stub
448         return null;
449       }
450
451       @Override
452       public ConnectionPropertyProviderI put(String key,
453               ConnectionPropertyProviderI value)
454       {
455         // TODO Auto-generated method stub
456         return null;
457       }
458
459       @Override
460       public void putAll(
461               Map<? extends String, ? extends ConnectionPropertyProviderI> m)
462       {
463         // TODO Auto-generated method stub
464
465       }
466
467       @Override
468       public ConnectionPropertyProviderI remove(Object key)
469       {
470         // TODO Auto-generated method stub
471         return null;
472       }
473
474       @Override
475       public int size()
476       {
477         // TODO Auto-generated method stub
478         return 0;
479       }
480
481       @Override
482       public Collection<ConnectionPropertyProviderI> values()
483       {
484         // TODO Auto-generated method stub
485         return null;
486       }
487
488     };
489   }
490
491 }