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