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