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