JAL-1807 explicit imports (jalview.util)
[jalview.git] / src / jalview / util / UrlLink.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 package jalview.util;
22
23 import java.util.Vector;
24
25 import com.stevesoft.pat.Regex;
26
27 public class UrlLink
28 {
29   /**
30    * helper class to parse URL Link strings taken from applet parameters or
31    * jalview properties file using the Regex implementation. Jalview 2.4
32    * extension allows regular expressions to be used to parse ID strings and
33    * replace the result in the URL. Regex's operate on the whole ID string given
34    * to the matchURL method, if no regex is supplied, then only text following
35    * the first pipe symbol will be susbstituted. Usage documentation todo.
36    */
37   private String url_suffix, url_prefix, target, label, regexReplace;
38
39   private boolean dynamic = false;
40
41   private String invalidMessage = null;
42
43   /**
44    * parse the given linkString of the form '<label>|<url>' into parts url may
45    * contain a string $SEQUENCE_ID<=optional regex=>$ where <=optional regex=>
46    * must be of the form =/<perl style regex>/=$
47    * 
48    * @param link
49    */
50   public UrlLink(String link)
51   {
52     int sep = link.indexOf("|"), psqid = link.indexOf("$SEQUENCE_ID");
53     if (psqid > -1)
54     {
55       dynamic = true;
56       int p = sep;
57       do
58       {
59         sep = p;
60         p = link.indexOf("|", sep + 1);
61       } while (p > sep && p < psqid);
62       // Assuming that the URL itself does not contain any '|' symbols
63       // sep now contains last pipe symbol position prior to any regex symbols
64       label = link.substring(0, sep);
65       if (label.indexOf("|") > -1)
66       {
67         // | terminated database name / www target at start of Label
68         target = label.substring(0, label.indexOf("|"));
69       }
70       else if (label.indexOf(" ") > 2)
71       {
72         // space separated Label - matches database name
73         target = label.substring(0, label.indexOf(" "));
74       }
75       else
76       {
77         target = label;
78       }
79       // Parse URL : Whole URL string first
80       url_prefix = link.substring(sep + 1, psqid);
81       if (link.indexOf("$SEQUENCE_ID=/") == psqid
82               && (p = link.indexOf("/=$", psqid + 14)) > psqid + 14)
83       {
84         // Extract Regex and suffix
85         url_suffix = link.substring(p + 3);
86         regexReplace = link.substring(psqid + 14, p);
87         try
88         {
89           Regex rg = Regex.perlCode("/"
90                   + regexReplace + "/");
91           if (rg == null)
92           {
93             invalidMessage = "Invalid Regular Expression : '"
94                     + regexReplace + "'\n";
95           }
96         } catch (Exception e)
97         {
98           invalidMessage = "Invalid Regular Expression : '" + regexReplace
99                   + "'\n";
100         }
101       }
102       else
103       {
104         regexReplace = null;
105         // verify format is really correct.
106         if (link.indexOf("$SEQUENCE_ID$") == psqid)
107         {
108           url_suffix = link.substring(psqid + 13);
109           regexReplace = null;
110         }
111         else
112         {
113           invalidMessage = "Warning: invalid regex structure for URL link : "
114                   + link;
115         }
116       }
117     }
118     else
119     {
120       target = link.substring(0, sep);
121       label = link.substring(0, sep = link.lastIndexOf("|"));
122       url_prefix = link.substring(sep + 1);
123       regexReplace = null; // implies we trim any prefix if necessary //
124       // regexReplace=".*\\|?(.*)";
125       url_suffix = null;
126     }
127   }
128
129   /**
130    * @return the url_suffix
131    */
132   public String getUrl_suffix()
133   {
134     return url_suffix;
135   }
136
137   /**
138    * @return the url_prefix
139    */
140   public String getUrl_prefix()
141   {
142     return url_prefix;
143   }
144
145   /**
146    * @return the target
147    */
148   public String getTarget()
149   {
150     return target;
151   }
152
153   /**
154    * @return the label
155    */
156   public String getLabel()
157   {
158     return label;
159   }
160
161   /**
162    * @return the regexReplace
163    */
164   public String getRegexReplace()
165   {
166     return regexReplace;
167   }
168
169   /**
170    * @return the invalidMessage
171    */
172   public String getInvalidMessage()
173   {
174     return invalidMessage;
175   }
176
177   /**
178    * Check if URL string was parsed properly.
179    * 
180    * @return boolean - if false then <code>getInvalidMessage</code> returns an
181    *         error message
182    */
183   public boolean isValid()
184   {
185     return invalidMessage == null;
186   }
187
188   /**
189    * return one or more URL strings by applying regex to the given idstring
190    * 
191    * @param idstring
192    * @param onlyIfMatches
193    *          - when true url strings are only made if regex is defined and
194    *          matches
195    * @return String[] { part of idstring substituted, full substituted url , ..
196    *         next part, next url..}
197    */
198   public String[] makeUrls(String idstring, boolean onlyIfMatches)
199   {
200     if (dynamic)
201     {
202       if (regexReplace != null)
203       {
204         Regex rg = Regex.perlCode("/" + regexReplace + "/");
205         if (rg.search(idstring))
206         {
207           int ns = rg.numSubs();
208           if (ns == 0)
209           {
210             // take whole regex
211             return new String[]
212             { rg.stringMatched(),
213                 url_prefix + rg.stringMatched() + url_suffix };
214           } /*
215              * else if (ns==1) { // take only subgroup match return new String[]
216              * { rg.stringMatched(1), url_prefix+rg.stringMatched(1)+url_suffix
217              * }; }
218              */
219           else
220           {
221             // debug
222             for (int s = 0; s <= rg.numSubs(); s++)
223             {
224               System.err.println("Sub " + s + " : " + rg.matchedFrom(s)
225                       + " : " + rg.matchedTo(s) + " : '"
226                       + rg.stringMatched(s) + "'");
227             }
228             // try to collate subgroup matches
229             Vector subs = new Vector();
230             // have to loop through submatches, collating them at top level
231             // match
232             int s = 0; // 1;
233             while (s <= ns)
234             {
235               if (s + 1 <= ns && rg.matchedTo(s) > -1
236                       && rg.matchedTo(s + 1) > -1
237                       && rg.matchedTo(s + 1) < rg.matchedTo(s))
238               {
239                 // s is top level submatch. search for submatches enclosed by
240                 // this one
241                 int r = s + 1;
242                 String mtch = "";
243                 while (r <= ns && rg.matchedTo(r) <= rg.matchedTo(s))
244                 {
245                   if (rg.matchedFrom(r) > -1)
246                   {
247                     mtch += rg.stringMatched(r);
248                   }
249                   r++;
250                 }
251                 if (mtch.length() > 0)
252                 {
253                   subs.addElement(mtch);
254                   subs.addElement(url_prefix + mtch + url_suffix);
255                 }
256                 s = r;
257               }
258               else
259               {
260                 if (rg.matchedFrom(s) > -1)
261                 {
262                   subs.addElement(rg.stringMatched(s));
263                   subs.addElement(url_prefix + rg.stringMatched(s)
264                           + url_suffix);
265                 }
266                 s++;
267               }
268             }
269
270             String[] res = new String[subs.size()];
271             for (int r = 0, rs = subs.size(); r < rs; r++)
272             {
273               res[r] = (String) subs.elementAt(r);
274             }
275             subs.removeAllElements();
276             return res;
277           }
278         }
279         if (onlyIfMatches)
280         {
281           return null;
282         }
283       }
284       /* Otherwise - trim off any 'prefix' - pre 2.4 Jalview behaviour */
285       if (idstring.indexOf("|") > -1)
286       {
287         idstring = idstring.substring(idstring.lastIndexOf("|") + 1);
288       }
289
290       // just return simple url substitution.
291       return new String[]
292       { idstring, url_prefix + idstring + url_suffix };
293     }
294     else
295     {
296       return new String[]
297       { "", url_prefix };
298     }
299   }
300
301   public String toString()
302   {
303     return label
304             + "|"
305             + url_prefix
306             + (dynamic ? ("$SEQUENCE_ID" + ((regexReplace != null) ? "="
307                     + regexReplace + "=$" : "$")) : "")
308             + ((url_suffix == null) ? "" : url_suffix);
309
310   }
311
312   private static void testUrls(UrlLink ul, String idstring, String[] urls)
313   {
314
315     if (urls == null)
316     {
317       System.out.println("Created NO urls.");
318     }
319     else
320     {
321       System.out.println("Created " + (urls.length / 2) + " Urls.");
322       for (int uls = 0; uls < urls.length; uls += 2)
323       {
324         System.out.println("URL Replacement text : " + urls[uls]
325                 + " : URL : " + urls[uls + 1]);
326       }
327     }
328   }
329
330   public static void main(String argv[])
331   {
332     String[] links = new String[]
333     {
334     /*
335      * "AlinkT|Target|http://foo.foo.soo/",
336      * "myUrl1|http://$SEQUENCE_ID=/[0-9]+/=$.someserver.org/foo",
337      * "myUrl2|http://$SEQUENCE_ID=/(([0-9]+).+([A-Za-z]+))/=$.someserver.org/foo"
338      * ,
339      * "myUrl3|http://$SEQUENCE_ID=/([0-9]+).+([A-Za-z]+)/=$.someserver.org/foo"
340      * , "myUrl4|target|http://$SEQUENCE_ID$.someserver.org/foo|too",
341      * "PF1|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/(?:PFAM:)?(.+)/=$"
342      * ,
343      * "PF2|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/(PFAM:)?(.+)/=$"
344      * ,
345      * "PF3|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/PFAM:(.+)/=$"
346      * , "NOTFER|http://notfer.org/$SEQUENCE_ID=/(?<!\\s)(.+)/=$",
347      */
348     "NESTED|http://nested/$SEQUENCE_ID=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
349     String[] idstrings = new String[]
350     {
351     /*
352      * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
353      * //"123123312", "123123 ABCDE foo", "PFAM:PF23943",
354      */
355     "Label:gi|9234|pdb|102L|A" };
356     // TODO: test the setLabel method.
357     for (int i = 0; i < links.length; i++)
358     {
359       UrlLink ul = new UrlLink(links[i]);
360       if (ul.isValid())
361       {
362         System.out.println("\n\n\n");
363         System.out.println("Link " + i + " " + links[i] + " : "
364                 + ul.toString());
365         System.out.println(" pref : "
366                 + ul.getUrl_prefix()
367                 + "\n suf : "
368                 + ul.getUrl_suffix()
369                 + "\n : "
370                 + ((ul.getRegexReplace() != null) ? ul.getRegexReplace()
371                         : ""));
372         for (int ids = 0; ids < idstrings.length; ids++)
373         {
374           System.out.println("ID String : " + idstrings[ids]
375                   + "\nWithout onlyIfMatches:");
376           String[] urls = ul.makeUrls(idstrings[ids], false);
377           testUrls(ul, idstrings[ids], urls);
378           System.out.println("With onlyIfMatches set.");
379           urls = ul.makeUrls(idstrings[ids], true);
380           testUrls(ul, idstrings[ids], urls);
381         }
382       }
383       else
384       {
385         System.err.println("Invalid URLLink : " + links[i] + " : "
386                 + ul.getInvalidMessage());
387       }
388     }
389   }
390
391   public boolean isDynamic()
392   {
393     // TODO Auto-generated method stub
394     return dynamic;
395   }
396
397   public void setLabel(String newlabel)
398   {
399     this.label = newlabel;
400   }
401 }