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