inprogress
[jalview.git] / forester / java / src / org / forester / io / parsers / util / ParserUtils.java
1 // $Id:
2 //
3 // FORESTER -- software libraries and applications
4 // for evolutionary biology research and applications.
5 //
6 // Copyright (C) 2008-2009 Christian M. Zmasek
7 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: www.phylosoft.org/
26
27 package org.forester.io.parsers.util;
28
29 import java.io.BufferedReader;
30 import java.io.File;
31 import java.io.FileNotFoundException;
32 import java.io.FileReader;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.StringReader;
37 import java.net.URL;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40
41 import org.forester.io.parsers.PhylogenyParser;
42 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
43 import org.forester.io.parsers.nhx.NHXParser;
44 import org.forester.io.parsers.nhx.NHXParser.TAXONOMY_EXTRACTION;
45 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
46 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
47 import org.forester.io.parsers.tol.TolParser;
48 import org.forester.phylogeny.Phylogeny;
49 import org.forester.phylogeny.PhylogenyMethods;
50 import org.forester.phylogeny.PhylogenyNode;
51 import org.forester.phylogeny.data.Identifier;
52 import org.forester.phylogeny.data.Taxonomy;
53 import org.forester.util.ForesterConstants;
54 import org.forester.util.ForesterUtil;
55
56 public final class ParserUtils {
57
58     final public static String   TAX_CODE                       = "(?:[A-Z9][A-Z]{2}[A-Z0-9]{2})|RAT|PIG|PEA|CAP";
59     final public static Pattern  TAXOMONY_SN_PATTERN            = Pattern
60                                                                         .compile( "[A-Z0-9]{2,}_([A-Z][a-z]+_[a-z]{2,}(?:_[a-z][a-z0-9_]+)?)\\b" );
61     final public static Pattern  TAXOMONY_CODE_PATTERN_R1       = Pattern.compile( "[A-Z0-9]+_(" + TAX_CODE
62                                                                         + ")(?:\\b|_)" );
63     final public static Pattern  TAXOMONY_CODE_PATTERN_R2       = Pattern.compile( "(?:\\b|_)(" + TAX_CODE
64                                                                         + ")(?:\\b|_)" );
65     final private static Pattern TAXOMONY_CODE_PATTERN_PF       = Pattern.compile( "[A-Z0-9]{2,}_(" + TAX_CODE
66                                                                         + ")/\\d+-\\d+" );
67     final public static Pattern  TAXOMONY_CODE_PATTERN_4        = Pattern.compile( "\\[(" + TAX_CODE + ")\\]" );
68     final public static Pattern  TAXOMONY_CODE_PATTERN_6        = Pattern.compile( "\\[([A-Z9][A-Z]{2}[A-Z0-9]{3})\\]" );
69     final private static Pattern TAXOMONY_UNIPROT_ID_PATTERN_1  = Pattern.compile( "\\b\\d{1,7}\\b" );
70     final private static Pattern TAXOMONY_UNIPROT_ID_PATTERN_2  = Pattern.compile( "(\\d{1,7})[^0-9A-Za-z].*" );
71     final private static Pattern TAXOMONY_UNIPROT_ID_PATTERN_PF = Pattern.compile( "(\\d{1,7})/\\d+-\\d+" );
72
73     final public static PhylogenyParser createParserDependingFileContents( final File file,
74                                                                            final boolean phyloxml_validate_against_xsd )
75             throws FileNotFoundException, IOException {
76         PhylogenyParser parser = null;
77         final String first_line = ForesterUtil.getFirstLine( file ).trim().toLowerCase();
78         if ( first_line.startsWith( "<" ) ) {
79             parser = new PhyloXmlParser();
80             if ( phyloxml_validate_against_xsd ) {
81                 final ClassLoader cl = PhyloXmlParser.class.getClassLoader();
82                 final URL xsd_url = cl.getResource( ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE );
83                 if ( xsd_url != null ) {
84                     ( ( PhyloXmlParser ) parser ).setValidateAgainstSchema( xsd_url.toString() );
85                 }
86                 else {
87                     if ( ForesterConstants.RELEASE ) {
88                         throw new RuntimeException( "failed to get URL for phyloXML XSD from jar file from ["
89                                 + ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE + "]" );
90                     }
91                 }
92             }
93         }
94         else if ( ( first_line.startsWith( "nexus" ) ) || ( first_line.startsWith( "#nexus" ) )
95                 || ( first_line.startsWith( "# nexus" ) ) || ( first_line.startsWith( "begin" ) ) ) {
96             parser = new NexusPhylogeniesParser();
97         }
98         else {
99             parser = new NHXParser();
100         }
101         return parser;
102     }
103
104     final public static PhylogenyParser createParserDependingOnFileType( final File file,
105                                                                          final boolean phyloxml_validate_against_xsd )
106             throws FileNotFoundException, IOException {
107         PhylogenyParser parser = null;
108         parser = ParserUtils.createParserDependingOnSuffix( file.getName(), phyloxml_validate_against_xsd );
109         if ( parser == null ) {
110             parser = createParserDependingFileContents( file, phyloxml_validate_against_xsd );
111         }
112         return parser;
113     }
114
115     /**
116      * Return null if it can not guess the parser to use based on name suffix.
117      * 
118      * @param filename
119      * @return
120      */
121     final public static PhylogenyParser createParserDependingOnSuffix( final String filename,
122                                                                        final boolean phyloxml_validate_against_xsd ) {
123         PhylogenyParser parser = null;
124         final String filename_lc = filename.toLowerCase();
125         if ( filename_lc.endsWith( ".tol" ) || filename_lc.endsWith( ".tolxml" ) || filename_lc.endsWith( ".tol.zip" ) ) {
126             parser = new TolParser();
127         }
128         else if ( filename_lc.endsWith( ".xml" ) || filename_lc.endsWith( ".px" ) || filename_lc.endsWith( "phyloxml" )
129                 || filename_lc.endsWith( ".zip" ) ) {
130             parser = new PhyloXmlParser();
131             if ( phyloxml_validate_against_xsd ) {
132                 final ClassLoader cl = PhyloXmlParser.class.getClassLoader();
133                 final URL xsd_url = cl.getResource( ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE );
134                 if ( xsd_url != null ) {
135                     ( ( PhyloXmlParser ) parser ).setValidateAgainstSchema( xsd_url.toString() );
136                 }
137                 else {
138                     if ( ForesterConstants.RELEASE ) {
139                         throw new RuntimeException( "failed to get URL for phyloXML XSD from jar file from ["
140                                 + ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE + "]" );
141                     }
142                 }
143             }
144         }
145         else if ( filename_lc.endsWith( ".nexus" ) || filename_lc.endsWith( ".nex" ) || filename_lc.endsWith( ".nx" ) ) {
146             parser = new NexusPhylogeniesParser();
147         }
148         else if ( filename_lc.endsWith( ".nhx" ) || filename_lc.endsWith( ".nh" ) || filename_lc.endsWith( ".newick" )
149                 || filename_lc.endsWith( ".nwk" ) ) {
150             parser = new NHXParser();
151         }
152         return parser;
153     }
154
155     final public static PhylogenyParser createParserDependingOnUrlContents( final URL url,
156                                                                             final boolean phyloxml_validate_against_xsd )
157             throws FileNotFoundException, IOException {
158         final String lc_filename = url.getFile().toString().toLowerCase();
159         PhylogenyParser parser = createParserDependingOnSuffix( lc_filename, phyloxml_validate_against_xsd );
160         if ( ( parser != null ) && lc_filename.endsWith( ".zip" ) ) {
161             if ( parser instanceof PhyloXmlParser ) {
162                 ( ( PhyloXmlParser ) parser ).setZippedInputstream( true );
163             }
164             else if ( parser instanceof TolParser ) {
165                 ( ( TolParser ) parser ).setZippedInputstream( true );
166             }
167         }
168         if ( parser == null ) {
169             final String first_line = ForesterUtil.getFirstLine( url ).trim().toLowerCase();
170             if ( first_line.startsWith( "<" ) ) {
171                 parser = new PhyloXmlParser();
172                 if ( phyloxml_validate_against_xsd ) {
173                     final ClassLoader cl = PhyloXmlParser.class.getClassLoader();
174                     final URL xsd_url = cl.getResource( ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE );
175                     if ( xsd_url != null ) {
176                         ( ( PhyloXmlParser ) parser ).setValidateAgainstSchema( xsd_url.toString() );
177                     }
178                     else {
179                         throw new RuntimeException( "failed to get URL for phyloXML XSD from jar file from ["
180                                 + ForesterConstants.LOCAL_PHYLOXML_XSD_RESOURCE + "]" );
181                     }
182                 }
183             }
184             else if ( ( first_line.startsWith( "nexus" ) ) || ( first_line.startsWith( "#nexus" ) )
185                     || ( first_line.startsWith( "# nexus" ) ) || ( first_line.startsWith( "begin" ) ) ) {
186                 parser = new NexusPhylogeniesParser();
187             }
188             else {
189                 parser = new NHXParser();
190             }
191         }
192         return parser;
193     }
194
195     public static BufferedReader createReader( final Object source ) throws IOException, FileNotFoundException {
196         BufferedReader reader = null;
197         if ( ( source instanceof File ) || ( source instanceof String ) ) {
198             File f = null;
199             if ( source instanceof File ) {
200                 f = ( File ) source;
201             }
202             else {
203                 f = new File( ( String ) source );
204             }
205             if ( !f.exists() ) {
206                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
207             }
208             else if ( !f.isFile() ) {
209                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
210             }
211             else if ( !f.canRead() ) {
212                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
213             }
214             reader = new BufferedReader( new FileReader( f ) );
215         }
216         else if ( source instanceof InputStream ) {
217             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
218         }
219         else if ( ( source instanceof StringBuffer ) || ( source instanceof StringBuilder ) ) {
220             reader = new BufferedReader( new StringReader( source.toString() ) );
221         }
222         else {
223             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
224                     + "] (can only parse objects of type File/String, InputStream, StringBuffer, or StringBuilder)" );
225         }
226         return reader;
227     }
228
229     public final static String extractTaxonomyCodeFromNodeName( final String name,
230                                                                 final TAXONOMY_EXTRACTION taxonomy_extraction ) {
231         if ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT ) {
232             final Matcher m = TAXOMONY_CODE_PATTERN_PF.matcher( name );
233             if ( m.find() ) {
234                 return m.group( 1 );
235             }
236         }
237         else if ( ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED )
238                 || ( taxonomy_extraction == TAXONOMY_EXTRACTION.AGGRESSIVE ) ) {
239             final Matcher m1 = TAXOMONY_CODE_PATTERN_R1.matcher( name );
240             if ( m1.find() ) {
241                 return m1.group( 1 );
242             }
243             final Matcher m2 = TAXOMONY_CODE_PATTERN_R2.matcher( name );
244             if ( m2.find() ) {
245                 return m2.group( 1 );
246             }
247         }
248         return null;
249     }
250
251     public final static String extractScientificNameFromNodeName( final String name ) {
252         final Matcher m1 = TAXOMONY_SN_PATTERN.matcher( name );
253         if ( m1.find() ) {
254             return m1.group( 1 ).replace( '_', ' ' );
255         }
256         return null;
257     }
258
259     public final static String extractTaxonomyDataFromNodeName( final PhylogenyNode node,
260                                                                 final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction )
261             throws PhyloXmlDataFormatException {
262         if ( taxonomy_extraction == TAXONOMY_EXTRACTION.NO ) {
263             throw new IllegalArgumentException();
264         }
265         final String id = extractUniprotTaxonomyIdFromNodeName( node.getName(), taxonomy_extraction );
266         if ( !ForesterUtil.isEmpty( id ) ) {
267             if ( !node.getNodeData().isHasTaxonomy() ) {
268                 node.getNodeData().setTaxonomy( new Taxonomy() );
269             }
270             node.getNodeData().getTaxonomy().setIdentifier( new Identifier( id, "uniprot" ) );
271             return id;
272         }
273         else {
274             final String code = extractTaxonomyCodeFromNodeName( node.getName(), taxonomy_extraction );
275             if ( !ForesterUtil.isEmpty( code ) ) {
276                 if ( !node.getNodeData().isHasTaxonomy() ) {
277                     node.getNodeData().setTaxonomy( new Taxonomy() );
278                 }
279                 node.getNodeData().getTaxonomy().setTaxonomyCode( code );
280                 return code;
281             }
282             else if ( ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED || taxonomy_extraction == TAXONOMY_EXTRACTION.AGGRESSIVE ) ) {
283                 final String sn = extractScientificNameFromNodeName( node.getName() );
284                 if ( !ForesterUtil.isEmpty( sn ) ) {
285                     if ( !node.getNodeData().isHasTaxonomy() ) {
286                         node.getNodeData().setTaxonomy( new Taxonomy() );
287                     }
288                     node.getNodeData().getTaxonomy().setScientificName( sn );
289                     return sn;
290                 }
291             }
292         }
293         return null;
294     }
295
296     public final static String extractUniprotTaxonomyIdFromNodeName( final String name,
297                                                                      final TAXONOMY_EXTRACTION taxonomy_extraction ) {
298         if ( ( name.indexOf( "_" ) > 0 )
299                 && ( ( ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED ) || ( taxonomy_extraction == TAXONOMY_EXTRACTION.AGGRESSIVE ) ) || ( ( ( name
300                         .indexOf( "/" ) > 4 ) && ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT ) ) ) ) ) {
301             final String[] s = name.split( "[_\\s]" );
302             if ( s.length > 1 ) {
303                 final String str = s[ 1 ];
304                 if ( !ForesterUtil.isEmpty( str ) ) {
305                     if ( taxonomy_extraction == TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT ) {
306                         final Matcher m = TAXOMONY_UNIPROT_ID_PATTERN_PF.matcher( str );
307                         if ( m.matches() ) {
308                             return m.group( 1 );
309                         }
310                     }
311                     else {
312                         final Matcher m1 = TAXOMONY_UNIPROT_ID_PATTERN_1.matcher( str );
313                         if ( m1.matches() ) {
314                             return m1.group();
315                         }
316                         final Matcher m2 = TAXOMONY_UNIPROT_ID_PATTERN_2.matcher( str );
317                         if ( m2.matches() ) {
318                             return m2.group( 1 );
319                         }
320                     }
321                 }
322             }
323         }
324         if ( taxonomy_extraction == TAXONOMY_EXTRACTION.AGGRESSIVE ) {
325             final Matcher m1 = TAXOMONY_UNIPROT_ID_PATTERN_1.matcher( name );
326             if ( m1.matches() ) {
327                 return name;
328             }
329         }
330         return null;
331     }
332
333     public final static Phylogeny[] readPhylogenies( final File file ) throws FileNotFoundException, IOException {
334         return PhylogenyMethods.readPhylogenies( ParserUtils.createParserDependingOnFileType( file, true ), file );
335     }
336
337     public final static Phylogeny[] readPhylogenies( final String file_name ) throws FileNotFoundException, IOException {
338         return readPhylogenies( new File( file_name ) );
339     }
340 }