JAL-2316 Added unit tests for CustomUrlProvider
[jalview.git] / src / jalview / urls / CustomUrlProvider.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21
22 package jalview.urls;
23
24 //import static jalview.util.UrlConstants.EMBLEBI_LABEL;
25 //import static jalview.util.UrlConstants.EMBLEBI_STRING;
26 //import static jalview.util.UrlConstants.SRS_LABEL;
27
28
29 import static jalview.util.UrlConstants.DB_ACCESSION;
30 import static jalview.util.UrlConstants.DELIM;
31 import static jalview.util.UrlConstants.SEP;
32 import static jalview.util.UrlConstants.SEQUENCE_ID;
33
34 import jalview.util.MessageManager;
35 import jalview.util.UrlLink;
36
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.Map;
40 import java.util.StringTokenizer;
41 import java.util.Vector;
42
43 /**
44  * 
45  * Implements the UrlProviderI interface for a UrlProvider object which serves
46  * custom URLs defined by the user
47  * 
48  * @author $author$
49  * @version $Revision$
50  */
51 public class CustomUrlProvider extends UrlProviderImpl
52 {
53
54   // minimum length of substitution in url link string
55   private static final int MIN_SUBST_LENGTH = 4;
56
57   // Default sequence URL link label for SRS
58   private static final String SRS_LABEL = "SRS";
59
60   // map of string ids to urlLinks
61   private HashMap<String, UrlLink> urls;
62
63   /**
64    * Construct UrlProvider for custom (user-entered) URLs
65    * 
66    * @param cachedUrlList
67    *          list of URLs in form stored in Cache. i.e. SEP delimited string
68    */
69   public CustomUrlProvider(String cachedUrlList)
70   {
71     try
72     {
73       urls = new HashMap<String, UrlLink>();
74
75       // cachedUrlList is in form <label>|<url>|<label>|<url>...
76       // parse cachedUrlList into labels (used as id) and url links
77       StringTokenizer st = new StringTokenizer(cachedUrlList, SEP);
78       while (st.hasMoreElements())
79       {
80         String name = st.nextToken();
81         String url = st.nextToken();
82         // check for '|' within a regex
83         int rxstart = url.indexOf(DELIM + DB_ACCESSION + DELIM);
84         if (rxstart == -1)
85         {
86           rxstart = url.indexOf(DELIM + SEQUENCE_ID + DELIM);
87         }
88         while (rxstart == -1 && url.indexOf("/=" + DELIM) == -1
89                 && st.hasMoreTokens())
90         {
91           url = url + SEP + st.nextToken();
92         }
93         urls.put(name, new UrlLink(name + SEP + url));
94       }
95     } catch (Exception ex)
96     {
97       System.out.println(ex + "\nError parsing sequence links");
98     }
99     upgradeOldLinks();
100
101   }
102
103   /**
104    * Construct UrlProvider for custom (user-entered) URLs
105    * 
106    * @param urlList
107    *          list of URLs as (label,url) pairs
108    */
109   public CustomUrlProvider(Map<String, String> urlList)
110   {
111     try
112     {
113       urls = new HashMap<String, UrlLink>();
114       Iterator<Map.Entry<String, String>> it = urlList.entrySet()
115               .iterator();
116       while (it.hasNext())
117       {
118         Map.Entry<String, String> pair = it.next();
119         urls.put(pair.getKey(),
120                 new UrlLink(pair.getKey() + SEP + pair.getValue()));
121       }
122     } catch (Exception ex)
123     {
124       System.out.println(ex + "\nError parsing sequence links");
125     }
126     upgradeOldLinks();
127   }
128
129   /*
130    * Upgrade any legacy links which may have been left lying around
131    */
132   private void upgradeOldLinks()
133   {
134     // upgrade old SRS link
135     if (urls.containsKey(SRS_LABEL))
136     {
137       urls.remove(SRS_LABEL);
138       urls.put(DEFAULT_LABEL, new UrlLink(DEFAULT_STRING));
139     }
140   }
141
142   @Override
143   public Vector<String> getLinksForDisplay()
144   {
145     Vector<String> links = new Vector<String>();
146     Iterator<Map.Entry<String, UrlLink>> it = urls.entrySet().iterator();
147     while (it.hasNext())
148     {
149       Map.Entry<String, UrlLink> pair = it.next();
150       links.add(pair.getValue().toString());
151     }
152     return links;
153   }
154
155   @Override
156   public boolean setDefaultUrl(String id)
157   {
158     if (urls.containsKey(id))
159     {
160       defaultUrl = id;
161     }
162     else
163     {
164       defaultUrl = null;
165     }
166     return urls.containsKey(id);
167   }
168
169   @Override
170   public String writeUrlsAsString()
171   {
172     StringBuffer links = new StringBuffer();
173     if (urls.size() > 0)
174     {
175       for (UrlLink link : urls.values())
176       {
177         links.append(link.toString());
178         links.append(SEP);
179       }
180
181       // remove last SEP
182       links.setLength(links.length() - 1);
183     }
184     else
185     {
186       urls.clear();
187     }
188     return links.toString();
189   }
190
191   @Override
192   public String getDefaultUrl(String seqid)
193   {
194     if (defaultUrl == null)
195     {
196       return null;
197     }
198
199     String url = null;
200     UrlLink urlLink = urls.get(defaultUrl);
201     String[] defaultUrls = urlLink.makeUrls(seqid, true);
202     if (defaultUrls == null || defaultUrls[0] == null
203             || defaultUrls[0].length() < MIN_SUBST_LENGTH)
204     {
205       url = null;
206     }
207     else
208     {
209       // just take first URL made from regex
210       url = defaultUrls[1];
211     }
212     return url;
213   }
214
215   @Override
216   public String getDefaultTarget(String seqid)
217   {
218     return urls.get(defaultUrl).getTarget();
219   }
220
221   @Override
222   public void setUrlLinks(Vector<String> names, Vector<String> urlstrings)
223   {
224     HashMap<String, UrlLink> newurls = new HashMap<String, UrlLink>();
225
226     // should check that lists are same length but this function is likely
227     // to change once the Preferences dialog is rebuilt
228
229     for (int i = 0; i < names.size(); ++i)
230     {
231       // don't allow MIRIAM ids as custom url names (as the links will overwrite
232       // each other)
233       // unlikely user would try to do this, but...
234       if (isMiriamId(names.elementAt(i)))
235       {
236         throw new IllegalArgumentException(MessageManager.formatMessage(
237                 "exception.url_cannot_have_miriam_id", names.elementAt(i)));
238       }
239       // don't allow duplicate key names as entries will be overwritten
240       if (newurls.containsKey(names.elementAt(i)))
241       {
242         throw new IllegalArgumentException(MessageManager.formatMessage(
243                 "exception.url_cannot_have_duplicate_id",
244                 names.elementAt(i)));
245       }
246       newurls.put(names.elementAt(i), new UrlLink(names.elementAt(i) + SEP
247               + urlstrings.elementAt(i)));
248     }
249
250     // don't update until we're sure this set is ok
251     urls = newurls;
252
253   }
254
255   @Override
256   public String chooseDefaultUrl()
257   {
258     // unilaterally set the default id to the EMBL_EBI link
259     
260     if (!urls.containsKey(DEFAULT_LABEL))
261     {
262       urls.put(DEFAULT_LABEL, new UrlLink(DEFAULT_STRING));
263     }
264     defaultUrl = DEFAULT_LABEL;
265     return DEFAULT_LABEL;
266   }
267
268 }