001    /*
002     * Copyright 2007, 2012 Stephen Fisher and Junhyong Kim, University of
003     * Pennsylvania.
004     *
005     * This file is part of Glo-DB.
006     * 
007     * Glo-DB is free software: you can redistribute it and/or modify it
008     * under the terms of the GNU General Public License as published by
009     * the Free Software Foundation, either version 3 of the License, or
010     * (at your option) any later version.
011     * 
012     * Glo-DB is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     * 
017     * You should have received a copy of the GNU General Public License
018     * along with Glo-DB. If not, see <http://www.gnu.org/licenses/>.
019     *
020     * @(#)GenBankTrack.java
021     */
022    
023    package edu.upenn.gloDB.io;
024    
025    import edu.upenn.gloDB.*;
026    import edu.upenn.gloDB.gui.GUIUtils;
027    import java.io.*;
028    import javax.swing.filechooser.FileFilter;
029    
030    /**
031     * Import/Export Track data from/to GenBank files.
032     *
033     * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
034     * THIS FILE IS A PLACE HOLDER
035     * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
036     *
037     * @author  Stephen Fisher
038     * @version $Id: GenBankTrack.java,v 1.1.2.13 2007/03/01 21:17:33 fisher Exp $
039     */
040    
041    public class GenBankTrack implements TrackFile {
042    
043             private final int ID = FileIO.GENBANK;
044             private final String DESC = "GenBank files (*.gb; *.genbank)";
045             private final String[] EXT = {".gb", ".genbank"};
046             private final FileFilter fileFilter = new GenBankFilter();
047    
048        //--------------------------------------------------------------------------
049        // Setters and Getters
050    
051             public int getID() { return ID; }
052    
053             public String getDesc() { return DESC; }
054    
055             public String[] getExt() { return EXT; }
056    
057             public FileFilter getFileFilter() { return fileFilter; }
058    
059        //--------------------------------------------------------------------------
060        // Miscellaneous Methods
061    
062             /**
063              * Load all Features in the GenBank file into a single Track and
064              * return the resulting Track object.
065              */
066             public Track load(String filename) {
067                      return load(filename, "");
068             }
069    
070             /**
071              * Load all Features in the GenBank file into a single Track and
072              * return the resulting Track object.
073              *
074              * @XXX need to throw FileIO exceptions, rather than just print
075              * errors.
076              */
077             public Track load(String filename, String seqID) {
078                      // when creating Track's ID, if necessary, remove ".gb"
079                      // filename extension
080                      String id = filename;
081                      if (id.endsWith(".gb")) id = id.substring(1, id.length()-5);
082                      if (id.endsWith(".genbank")) id = id.substring(1, id.length()-10);
083                      Track track = new Track(false, id);
084    
085                      Sequence srcSequence = null;
086                      if (seqID.length() > 0) srcSequence = ObjectHandles.getSequence(seqID);
087    
088                      try {
089                                    BufferedReader bReader = new BufferedReader(new FileReader(filename));
090    
091                                    String line;
092                                    boolean firstFeat = true;
093    
094                                    Feature feature  = null;  // current Feature
095    
096                                    while ((line = bReader.readLine()).trim() != null) {
097                                             // skip all comment lines
098                                             if (! line.startsWith("#")) {
099                                                      if (! firstFeat) {
100                                                                    // not first Feature so append existing Feature
101                                                                    // before reseting the variables for the next
102                                                                    // Feature.
103                                                                    track.addFeature(feature);
104                                                      } else {
105                                                                    firstFeat = false;
106                                                      }
107                                                      
108                                                      // split line at every space
109                                                      String[] fields = line.split(" ");
110                                                      
111                                                      // get a reference to the Sequence for this
112                                                      // Feature.  If no Sequence is found, then don't
113                                                      // add this Feature.  If srcSequence already
114                                                      // exists, then just use that instead.
115                                                      Sequence seqRef;
116                                                      if (srcSequence == null) {
117                                                                    seqRef = ObjectHandles.getSequence(fields[0]);
118                                                                    if (seqRef == null) continue;
119                                                      } else {
120                                                                    seqRef = srcSequence;
121                                                      }
122    
123                                                      // create a new Feature object
124                                                      feature = new ExactFeature(Integer.parseInt(fields[3]), 
125                                                                                                                                     Integer.parseInt(fields[4]), seqRef); 
126    
127                                                      // get Feature attributes
128                                                      String attributes = "";
129                                                      attributes += "source=" + fields[1];    // add source
130                                                      attributes += ";track=" + fields[2];   // add track
131                                                      attributes += ";score=" + fields[5];     // add score
132                                                      attributes += ";strand=" + fields[6];    // add strand
133                                                      attributes += ";frame=" + fields[7];     // add frame
134                                                      if (fields.length > 8) {
135                                                                    attributes += ";attribs=" + fields[8];      // get attributes
136                                                                    if (fields.length > 9) {
137                                                                             attributes += ";comments=" + fields[9]; // get comments
138                                                                    }
139                                                      }
140                                                      feature.setAttributes(attributes);
141    
142                                                      // add the Feature object to the Track
143                                                      track.addFeature(feature);
144                                             }
145    
146                                             // add last Features info
147                                             if (feature != null) track.addFeature(feature);
148                                    }
149    
150                                    bReader.close();
151                      } catch (FileNotFoundException e) {
152                                    GloDBUtils.printError("File not found: " + e.getMessage());
153                                    return null;
154                      } catch (IOException e) {
155                                    GloDBUtils.printError("Error reading file: " + filename);
156                                    return null;
157                      }
158    
159                      if (track.numFeatures() == 0) {
160                                    // this assumes an empty Track is a mistake, so return null
161                                    GloDBUtils.printError("Unable to load any features from the file: " + filename);
162                                    return null;
163                      }
164    
165                      // add track to trackPool
166                      try {
167                                    ObjectHandles.addTrack(track);
168                      } catch (InvalidIDException e) {
169                                    String id_new = Track.randomID("_T");
170                                    String msg = "ID \"" + track.getID() + "\" already exists, using ID \"" + id_new + "\" instead.";
171                                    GloDBUtils.printWarning(msg);
172                                    
173                                    // add self to set of all Tracks, using new ID
174                                    track.setID(id_new, false);
175                                    ObjectHandles.addTrack(track);
176                      }
177    
178                      GloDBUtils.printMsg("Loaded GenBank file: " + filename);
179                      return track;
180             }
181    
182             /** 
183              * Save the Track to a file based on it's ID.  This will
184              * overwrite any existing file and append ".gb" to the filename,
185              * if necessary.
186              */
187             public void save(String id) {
188                      // add ".gb" filename extension, if necessary
189                      String filename = id;
190                      if ((! filename.endsWith(".gb")) || (! filename.endsWith(".genbank"))) {
191                                    filename += ".gb";
192                      }
193    
194                      save(id, filename, true);
195             }
196    
197             /**
198              * Save all Features in a GloDB file.
199              *
200              * @XXX need to throw FileIO exceptions, rather than just print
201              * errors.
202              * @XXX Should offer option to include Sequence data.
203              */
204             public void save(String id, String filename, boolean overwrite) {
205                      // add ".gb" filename extension, if necessary
206                      if ((! filename.endsWith(".gb")) && (! filename.endsWith(".genbank"))) {
207                                    filename += ".gb";
208                      }
209    
210                      File file = new File(filename);
211                      // if the file already exists and not supposed to overwrite
212                      // it, then return on error.
213                      if (file.exists() && (! overwrite)) {
214                                    GloDBUtils.printMsg("ERROR: file \"" + filename + "\" already exists.");
215                                    return;
216                      }
217    
218                      try {
219                                    FileOutputStream fStream = new FileOutputStream(file);
220                                    ObjectOutputStream oStream = new ObjectOutputStream(fStream);
221                                    Track f = ObjectHandles.getTrack(id);
222                                    oStream.writeObject(f);
223                                    oStream.flush();
224                                    oStream.close();
225                      } catch (FileNotFoundException e) {
226                                    // problem with FileOutputStream
227                                    GloDBUtils.printMsg("ERROR: file \"" + filename + "\" can not be opened.");
228                      } catch (IOException e) {
229                                    // problem with ObjectOutputStream.  XXX do we need to
230                                    // close 'oStream'?
231                                    GloDBUtils.printMsg("ERROR: writting output file \"" + filename + "\".");
232                      }
233             }
234    
235             /** 
236              * GenBank specific FileFilter. 
237              * @XXX This should use EXT.
238              */
239             private class GenBankFilter extends FileFilter {
240                      public boolean accept(File f) {
241                                    // accept directories
242                                    if (f.isDirectory()) return true;
243    
244                                    // if true, then don't filter by file extensions.
245                                    if (GUIUtils.showAllFiles()) return true;
246    
247                                    // accept files ending in '.genbank' or '.gb'
248                                    if ((f.getName()).endsWith(".genbank")) return true;
249                                    if ((f.getName()).endsWith(".gb")) return true;
250    
251                                    return false;
252                      }
253                      
254                      // set the filter's description
255                      public String getDescription() { return DESC; }
256             }
257    
258    } // GenBankTrack.java
259    
260