2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.api.AlignViewportI;
24 import jalview.util.MessageManager;
26 import java.io.BufferedReader;
28 import java.io.FileInputStream;
29 import java.io.FileReader;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.io.Reader;
34 import java.io.StringReader;
35 import java.net.MalformedURLException;
37 import java.util.zip.GZIPInputStream;
40 * implements a random access wrapper around a particular datasource, for
41 * passing to identifyFile and AlignFile objects.
43 public class FileParse
46 * text specifying source of data. usually filename or url.
48 private String dataName = "unknown source";
50 public File inFile = null;
52 private AlignViewportI viewport;
54 public int index = 1; // sequence counter for FileParse object created from
58 protected char suffixSeparator = '#';
61 * character used to write newlines
63 protected String newline = System.getProperty("line.separator");
65 public void setNewlineString(String nl)
70 public String getNewlineString()
76 * '#' separated string tagged on to end of filename or url that was clipped
77 * off to resolve to valid filename
79 protected String suffix = null;
81 protected String type = null;
83 protected BufferedReader dataIn = null;
85 protected String errormessage = "UNITIALISED SOURCE";
87 protected boolean error = true;
89 protected String warningMessage = null;
92 * size of readahead buffer used for when initial stream position is marked.
94 final int READAHEAD_LIMIT = 2048;
101 * Create a new FileParse instance reading from the same datasource starting
102 * at the current position. WARNING! Subsequent reads from either object will
103 * affect the read position of the other, but not the error state.
107 public FileParse(FileParse from) throws IOException
111 throw new Error(MessageManager.getString("error.implementation_error_null_fileparse"));
117 index = ++from.index;
118 inFile = from.inFile;
119 suffixSeparator = from.suffixSeparator;
120 suffix = from.suffix;
121 errormessage = from.errormessage; // inherit potential error messages
122 error = false; // reset any error condition.
124 dataIn = from.dataIn;
129 dataName = from.dataName;
133 * Attempt to open a file as a datasource. Sets error and errormessage if
134 * fileStr was invalid.
137 * @return this.error (true if the source was invalid)
139 private boolean checkFileSource(String fileStr) throws IOException
142 this.inFile = new File(fileStr);
143 // check to see if it's a Jar file in disguise.
144 if (!inFile.exists())
146 errormessage = "FILE NOT FOUND";
149 if (!inFile.canRead())
151 errormessage = "FILE CANNOT BE OPENED FOR READING";
154 if (inFile.isDirectory())
156 // this is really a 'complex' filetype - but we don't handle directory
158 errormessage = "FILE IS A DIRECTORY";
163 if (fileStr.toLowerCase().endsWith(".gz"))
167 dataIn = tryAsGzipSource(new FileInputStream(fileStr));
170 } catch (Exception x)
172 warningMessage = "Failed to resolve as a GZ stream ("
173 + x.getMessage() + ")";
174 // x.printStackTrace();
179 dataIn = new BufferedReader(new FileReader(fileStr));
185 private BufferedReader tryAsGzipSource(InputStream inputStream)
188 BufferedReader inData = new BufferedReader(new InputStreamReader(
189 new GZIPInputStream(inputStream)));
196 private boolean checkURLSource(String fileStr) throws IOException,
197 MalformedURLException
199 errormessage = "URL NOT FOUND";
200 URL url = new URL(fileStr);
202 // GZIPInputStream code borrowed from Aquaria (soon to be open sourced) via
205 if (fileStr.toLowerCase().endsWith(".gz"))
209 InputStream inputStream = url.openStream();
210 dataIn = tryAsGzipSource(inputStream);
213 } catch (Exception ex)
221 dataIn = new BufferedReader(new InputStreamReader(url.openStream()));
222 } catch (IOException q)
226 throw new IOException(MessageManager.getString("exception.failed_to_resolve_gzip_stream"), e);
230 // record URL as name of datasource.
236 * sets the suffix string (if any) and returns remainder (if suffix was
240 * @return truncated fileStr or null
242 private String extractSuffix(String fileStr)
244 // first check that there wasn't a suffix string tagged on.
245 int sfpos = fileStr.lastIndexOf(suffixSeparator);
246 if (sfpos > -1 && sfpos < fileStr.length() - 1)
248 suffix = fileStr.substring(sfpos + 1);
249 // System.err.println("DEBUG: Found Suffix:"+suffix);
250 return fileStr.substring(0, sfpos);
256 * Create a datasource for input to Jalview. See AppletFormatAdapter for the
257 * types of sources that are handled.
260 * - datasource locator/content
262 * - protocol of source
263 * @throws MalformedURLException
264 * @throws IOException
266 public FileParse(String fileStr, String type)
267 throws MalformedURLException, IOException
272 if (type.equals(AppletFormatAdapter.FILE))
274 if (checkFileSource(fileStr))
276 String suffixLess = extractSuffix(fileStr);
277 if (suffixLess != null)
279 if (checkFileSource(suffixLess))
281 throw new IOException(MessageManager.formatMessage("exception.problem_opening_file_also_tried", new String[]{inFile.getName(),suffixLess,errormessage}));
286 throw new IOException(MessageManager.formatMessage("exception.problem_opening_file", new String[]{inFile.getName(),errormessage}));
290 else if (type.equals(AppletFormatAdapter.URL))
296 checkURLSource(fileStr);
297 if (suffixSeparator == '#')
299 extractSuffix(fileStr); // URL lref is stored for later reference.
301 } catch (IOException e)
303 String suffixLess = extractSuffix(fileStr);
304 if (suffixLess == null)
312 checkURLSource(suffixLess);
313 } catch (IOException e2)
315 errormessage = "BAD URL WITH OR WITHOUT SUFFIX";
316 throw (e); // just pass back original - everything was wrong.
320 } catch (Exception e)
322 errormessage = "CANNOT ACCESS DATA AT URL '" + fileStr + "' ("
323 + e.getMessage() + ")";
327 else if (type.equals(AppletFormatAdapter.PASTE))
329 errormessage = "PASTE INACCESSIBLE!";
330 dataIn = new BufferedReader(new StringReader(fileStr));
333 else if (type.equals(AppletFormatAdapter.CLASSLOADER))
335 errormessage = "RESOURCE CANNOT BE LOCATED";
336 java.io.InputStream is = getClass()
337 .getResourceAsStream("/" + fileStr);
340 String suffixLess = extractSuffix(fileStr);
341 if (suffixLess != null)
343 is = getClass().getResourceAsStream("/" + suffixLess);
348 dataIn = new BufferedReader(new java.io.InputStreamReader(is));
358 errormessage = "PROBABLE IMPLEMENTATION ERROR : Datasource Type given as '"
359 + (type != null ? type : "null") + "'";
362 if (dataIn == null || error)
364 // pass up the reason why we have no source to read from
365 throw new IOException(MessageManager.formatMessage("exception.failed_to_read_data_from_source", new String[]{errormessage}));
368 dataIn.mark(READAHEAD_LIMIT);
372 * mark the current position in the source as start for the purposes of it
373 * being analysed by IdentifyFile().identify
375 * @throws IOException
377 public void mark() throws IOException
381 dataIn.mark(READAHEAD_LIMIT);
385 throw new IOException(MessageManager.getString("exception.no_init_source_stream"));
389 public String nextLine() throws IOException
393 return dataIn.readLine();
395 throw new IOException(MessageManager.formatMessage("exception.invalid_source_stream", new String[]{errormessage}));
398 public boolean isValid()
404 * closes the datasource and tidies up. source will be left in an error state
406 public void close() throws IOException
408 errormessage = "EXCEPTION ON CLOSE";
412 errormessage = "SOURCE IS CLOSED";
416 * rewinds the datasource the beginning.
419 public void reset() throws IOException
421 if (dataIn != null && !error)
427 throw new IOException(MessageManager.getString("error.implementation_error_reset_called_for_invalid_source"));
433 * @return true if there is a warning for the user
435 public boolean hasWarningMessage()
437 return (warningMessage != null && warningMessage.length() > 0);
442 * @return empty string or warning message about file that was just parsed.
444 public String getWarningMessage()
446 return warningMessage;
449 public String getInFile()
453 return inFile.getAbsolutePath() + " (" + index + ")";
457 return "From Paste + (" + index + ")";
462 * @return the dataName
464 public String getDataName()
470 * set the (human readable) name or URI for this datasource
474 protected void setDataName(String dataname)
480 * get the underlying bufferedReader for this data source.
482 * @return null if no reader available
483 * @throws IOException
485 public Reader getReader()
487 if (dataIn != null) // Probably don't need to test for readiness &&
495 public AlignViewportI getViewport()
500 public void setViewport(AlignViewportI viewport)
502 this.viewport = viewport;