JAL-3691 automatic insertion of Locale.ROOT to toUpperCase() and toLowerCase() and...
[jalview.git] / src / jalview / io / packed / ParsePackedSet.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.io.packed;
22
23 import java.util.Locale;
24
25 import jalview.api.FeatureColourI;
26 import jalview.datamodel.AlignmentI;
27 import jalview.io.AppletFormatAdapter;
28 import jalview.io.FileFormatI;
29 import jalview.io.FileParse;
30 import jalview.io.FormatAdapter;
31 import jalview.io.IdentifyFile;
32 import jalview.io.packed.DataProvider.JvDataType;
33
34 import java.io.BufferedReader;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39
40 public class ParsePackedSet
41 {
42
43   /**
44    * return results as a series of jalview.datamodel objects suitable for
45    * display
46    * 
47    * @param context
48    *          - context which is updated with new data
49    * @param files
50    *          - source data
51    * @return list of data objects added to context
52    * @throws Exception
53    */
54   public Object[] getAlignment(JalviewDataset context,
55           Iterable<DataProvider> files) throws Exception
56   {
57     List<Object> rslt = new ArrayList<>();
58     if (context == null)
59     {
60       context = new JalviewDataset();
61     }
62     boolean deuniquify = false;
63     for (DataProvider dta : files)
64     {
65       Exception exerror = null;
66       String errmsg = null;
67       FileParse src = dta.getDataSource();
68       if (dta.getType().equals(DataProvider.JvDataType.ALIGNMENT))
69       {
70         FileFormatI fmt = null;
71         try
72         {
73           fmt = new IdentifyFile().identify(src, false);
74         } catch (Exception ex)
75         {
76           exerror = ex;
77           errmsg = "Couldn't identify alignment format.";
78         }
79
80         if (fmt != null)
81         {
82           // parse the alignment
83           AlignmentI al = null;
84           try
85           {
86             al = new FormatAdapter().readFromFile(src, fmt);
87           } catch (Exception e)
88           {
89             errmsg = "Failed to parse alignment from result set";
90             exerror = e;
91           }
92           if (al != null)
93           {
94             // deuniquify and construct/merge additional dataset entries if
95             // necessary.
96             context.addAlignment(al);
97             context.updateSetModified(true);
98             rslt.add(al);
99             deuniquify = true;
100           }
101         }
102       }
103       if (dta.getType().equals(JvDataType.ANNOTATION))
104       {
105         if (!context.hasAlignments())
106         {
107           errmsg = "No alignment or sequence dataset to associate annotation with.";
108           // could duplicate the dataset reference here as default behaviour for
109           // sequence associated annotation ?
110         }
111         try
112         {
113           BufferedReader br;
114           if (src.getReader() instanceof BufferedReader)
115           {
116             br = (BufferedReader) src.getReader();
117           }
118           else
119           {
120             br = new BufferedReader(src.getReader());
121           }
122           // TODO: add columnSelection to context
123           if (new jalview.io.AnnotationFile().parseAnnotationFrom(
124                   context.getLastAlignment(), null, br))
125           {
126             context.updateSetModified(true);
127           }
128           else
129           {
130             errmsg = "Annotation file contained no data.";
131           }
132
133         } catch (Exception e)
134         {
135           errmsg = ((errmsg == null) ? "" : errmsg)
136                   + "Failed to parse the annotation file associated with the alignment.";
137           exerror = e;
138         }
139       }
140       if (dta.getType().equals(JvDataType.SEQASSOCATED))
141       {
142         if (!context.hasSequenceAssoc())
143         {
144           errmsg = "No sequence to associate data with.";
145
146         }
147         errmsg = "parsing of sequence associated data is not implemented";
148         exerror = new Exception(errmsg);
149       }
150       if (dta.getType().equals(JvDataType.FEATURES))
151       {
152         // check the context has a place to store feature rendering definitions,
153         // if not, create one.
154         if (context.featureColours == null)
155         {
156           context.featureColours = new HashMap<>();
157         }
158         try
159         {
160           jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(src);
161           context.updateSetModified(ff.parse(context.getLastAlignment(),
162                   context.featureColours, false,
163                   context.relaxedIdMatching));
164         } catch (Exception e)
165         {
166           errmsg = ("Failed to parse the Features file associated with the alignment.");
167           exerror = e;
168         }
169       }
170       if (dta.getType().equals(JvDataType.TREE))
171       {
172         try
173         {
174           jalview.io.NewickFile nf = new jalview.io.NewickFile(src);
175           if (!nf.isValid())
176           {
177             nf.close();
178             nf = null;
179           }
180           else
181           {
182             // do association to current alignment.
183
184             context.addTreeFromFile(nf);
185             rslt.add(nf);
186             context.updateSetModified(true);
187           }
188         } catch (Exception e)
189         {
190           errmsg = ("Failed to parse the treeFile associated with the result.");
191           exerror = e;
192         }
193
194       }
195       if (exerror != null)
196       {
197         if (errmsg != null && errmsg.length() > 0)
198         {
199           throw new IOException(errmsg, exerror);
200         }
201         else
202         {
203           throw new IOException(errmsg, exerror);
204         }
205       }
206       else
207       {
208         if (errmsg != null && errmsg.length() > 0)
209         {
210           throw new IOException(errmsg);
211         }
212       }
213     }
214     if (deuniquify)
215     {
216       context.getLastAlignmentSet().deuniquifyAlignment();
217     }
218     return rslt.toArray();
219   }
220
221   /**
222    * simple command line test. Arguments should be one or more pairs of
223    * <DataProvider.JvDataType> <Filename> arguments. The routine will attempt to
224    * read each source in turn, and report what kind of Jalview datamodel objects
225    * would be created.
226    * 
227    * @param args
228    * @j2sIgnore
229    */
230   public static void main(String args[])
231   {
232     // make data providers from the set of keys/files
233     int i = 0;
234     List<DataProvider> dp = new ArrayList<>();
235     while ((i + 1) < args.length)
236     {
237       String type = args[i++];
238       final String file = args[i++];
239       final JvDataType jtype = DataProvider.JvDataType
240               .valueOf(type.toUpperCase(Locale.ROOT));
241       if (jtype != null)
242       {
243         final FileParse fp;
244         try
245         {
246           fp = new FileParse(file, AppletFormatAdapter.checkProtocol(file));
247         } catch (Exception e)
248         {
249           System.err.println("Couldn't handle datasource of type " + jtype
250                   + " using URI " + file);
251           e.printStackTrace();
252           return;
253         }
254         dp.add(new SimpleDataProvider(jtype, fp, null));
255       }
256       else
257       {
258         System.out.println("Couldn't parse source type token '"
259                 + type.toUpperCase(Locale.ROOT) + "'");
260       }
261     }
262     if (i < args.length)
263     {
264       System.out.print("** WARNING\nIgnoring unused arguments:\n");
265       while (i < args.length)
266       {
267         System.out.print(" " + args[i]);
268       }
269       System.out.print("\n");
270
271     }
272     System.out.println("Now trying to parse set:");
273     JalviewDataset context;
274     Object[] newdm;
275     ParsePackedSet pps;
276     try
277     {
278       newdm = (pps = new ParsePackedSet())
279               .getAlignment(context = new JalviewDataset(), dp);
280     } catch (Exception e)
281     {
282       System.out.println("Test failed for these arguments.\n");
283       e.printStackTrace(System.out);
284       return;
285     }
286     if (newdm != null)
287     {
288       for (Object o : newdm)
289       {
290         System.out.println("Will need to create an " + o.getClass());
291       }
292
293       // now test uniquify/deuniquify stuff
294       // uniquify alignment and write alignment, annotation, features, and trees
295       // to buffers.
296       // import with deuniquify info, and compare results to input.
297
298     }
299     else
300     {
301       if (context.getLastAlignmentSet().isModified())
302       {
303         System.err.println(
304                 "Initial alignment set was modified and any associated views should be updated.");
305       }
306     }
307   }
308 }