applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / VamsasArchiveReader.java
1 /*\r
2  * This file is part of the Vamsas Client version 0.1. \r
3  * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
4  *  Andrew Waterhouse and Dominik Lindner.\r
5  * \r
6  * Earlier versions have also been incorporated into Jalview version 2.4 \r
7  * since 2008, and TOPALi version 2 since 2007.\r
8  * \r
9  * The Vamsas Client is free software: you can redistribute it and/or modify\r
10  * it under the terms of the GNU Lesser General Public License as published by\r
11  * the Free Software Foundation, either version 3 of the License, or\r
12  * (at your option) any later version.\r
13  *  \r
14  * The Vamsas Client is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU Lesser General Public License for more details.\r
18  * \r
19  * You should have received a copy of the GNU Lesser General Public License\r
20  * along with the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.\r
21  */\r
22 package uk.ac.vamsas.client.simpleclient;\r
23 \r
24 import java.io.File;\r
25 import java.io.IOException;\r
26 import java.io.InputStream;\r
27 import java.io.BufferedInputStream;\r
28 import java.io.FileInputStream;\r
29 import java.io.RandomAccessFile;\r
30 import java.util.Enumeration;\r
31 import java.util.Hashtable;\r
32 import java.util.Iterator;\r
33 import java.util.Vector;\r
34 import org.apache.tools.zip.*;\r
35 import org.apache.commons.logging.Log;\r
36 import org.apache.commons.logging.LogFactory;\r
37 \r
38 import uk.ac.vamsas.client.AppDataInputStream;\r
39 import uk.ac.vamsas.objects.utils.document.VersionEntries;\r
40 \r
41 /**\r
42  * Basic methods for accessing an existing Vamsas Archive, and Jar entry names\r
43  * for creating new vamsas archives.\r
44  * \r
45  * @author jimp\r
46  * \r
47  */\r
48 public class VamsasArchiveReader {\r
49   private static final int JARFILE_OPEN_RETRIES = 50;\r
50 \r
51   private static final int JARFILE_OPEN_RETRYWAIT = 1;\r
52 \r
53   private static Log log = LogFactory.getLog(VamsasArchiveReader.class);\r
54 \r
55   ZipFile jfile = null;\r
56 \r
57   String jfileName = "randomAccessFile";\r
58 \r
59   boolean stream = false; // true if we are seeking on the stream.\r
60 \r
61   RandomAccessFile rfile;\r
62 \r
63   // ZipInputStream jstream=null;\r
64   Hashtable strmentries = null;\r
65 \r
66   private void streamInit() {\r
67     // throw new Error("VamsasArchiveReader(Stream) Not implemented!");\r
68     if (!stream) {\r
69       log.debug("Skipping init for Jar Stream input.");\r
70       return;\r
71     } else {\r
72       throw new Error(\r
73           "Implementation error - we don't do streams - only files or RA files");\r
74     }\r
75     /*\r
76      * strmentries = new Hashtable();\r
77      * log.debug("Jar Stream input Initialisation"); try { rfile.seek(0); // no\r
78      * buffering - we need to be able to move around the random access stream.\r
79      * jstream = new ZipInputStream(new FileInputStream(rfile.getFD())); // no\r
80      * manifest (probably) if (jstream.available()==0)\r
81      * log.warn("Can't read from JarInputStream (Locked stream!)"); ZipEntry\r
82      * entry=null; long pos=0; do { if ((entry=jstream.getNextEntry())!=null) {\r
83      * if (strmentries.containsKey(entry.getName())) {\r
84      * log.info("Only recording last of duplicate entries '"\r
85      * +entry.getName()+"'"); } strmentries.put(entry.getName(), new\r
86      * Long(pos++)); jstream.closeEntry(); } } while (entry!=null); } catch\r
87      * (Exception e) { log.warn("Exceptions during init!",e); jstream=null; }\r
88      */\r
89   }\r
90 \r
91   public VamsasArchiveReader(File vamsasfile) {\r
92     jfile = null;\r
93     int retries = JARFILE_OPEN_RETRIES;\r
94     Exception ex = null;\r
95     if (vamsasfile.exists()) {\r
96       while (jfile == null && --retries > 0) {\r
97         try {\r
98           jfile = new ZipFile(vamsasfile);\r
99           jfileName = vamsasfile.toString();\r
100         } catch (Exception e) {\r
101           ex = e;\r
102           jfile = null;\r
103           try {\r
104             Thread.sleep(JARFILE_OPEN_RETRYWAIT);\r
105           } catch (Exception w) {\r
106           }\r
107           ;\r
108         }\r
109       }\r
110       if (jfile == null && ex != null) {\r
111         log.debug("non-serious? Exceptions when opening JarFile at "\r
112             + vamsasfile, ex);\r
113       }\r
114     }\r
115   }\r
116 \r
117   /**\r
118    * in an ideal world - this constructor will create a reader object for the\r
119    * locked file's random access stream.\r
120    * \r
121    * @param vamsaslock\r
122    */\r
123   public VamsasArchiveReader(Lock vamsaslock) {\r
124     jfile = null;\r
125     if (vamsaslock == null || !vamsaslock.isLocked())\r
126       throw new Error(\r
127           "IMPLEMENTATION ERROR: Cannot create a VamsasArchiveReader without a valid lock.");\r
128     // throw new\r
129     // Error("VamsasArchiveReading from locked IO stream not yet implemented.");\r
130     try {\r
131       rfile = vamsaslock.getRaFile();\r
132       jfile = new ZipFile(rfile);\r
133       if (vamsaslock.target != null)\r
134         jfileName = vamsaslock.target.toString();\r
135     } catch (Exception e) {\r
136       rfile = null;\r
137       jfile = null;\r
138       log.warn(\r
139           "Unexpected IO Exception when accessing locked vamsas archive stream "\r
140               + vamsaslock.target, e);\r
141     }\r
142     /*\r
143      * stream = true; streamInit(); if (jstream==null) throw new\r
144      * Error("Failed to open archive from Locked random access stream.");\r
145      */\r
146   }\r
147 \r
148   /**\r
149    * the vamsas document version(s) handled by this Reader\r
150    */\r
151   final public static String DOCUMENT_VERSION = VersionEntries.BETA_VERSION;\r
152 \r
153   /**\r
154    * name of the jarEntry containing a well formatted vamsas XML Document\r
155    */\r
156 \r
157   final public static String VAMSASDOC = "vamsasDocument.xml";\r
158 \r
159   /**\r
160    * name of the jarEntry containing a root VAMSAS element, and containing a\r
161    * random sequence of VAMSAS DataSet elements\r
162    */\r
163 \r
164   final public static String VAMSASXML = "vamsas.xml";\r
165 \r
166   /**\r
167    * seeks jstream to the given entry name and reads it.\r
168    * \r
169    * @param entryname\r
170    * @return private JarEntry seekEntry(String entryname) { if (jstream==null)\r
171    *         return null; if (!strmentries.containsKey(entryname)) return null;\r
172    *         Long entrypos = (Long) strmentries.get(entryname); if\r
173    *         (entrypos==null) { log.error("Null entry position for "+entryname);\r
174    *         return null; } try { jstream=null; rfile.seek(0); jstream = new\r
175    *         ZipInputStream(new FileInputStream(rfile.getFD())); ZipEntry entry\r
176    *         = null; long epos = entrypos.longValue(); do { entry =\r
177    *         jstream.getNextEntry(); } while (entry!=null && --epos>=0); //\r
178    *         rfile.seek(entrypos.longValue()); // make a Jar entry from a zip\r
179    *         entry. return new JarEntry(entry); } catch (Exception e) {\r
180    *         log.warn("Whilst seeking for "+entryname, e); } return null; }\r
181    */\r
182   /**\r
183    * \r
184    * @return JarEntry for VamsasArchiveReader.VAMSASDOC\r
185    */\r
186   protected ZipEntry getVamsasDocumentEntry() {\r
187     return getJarEntry(VAMSASDOC);\r
188   }\r
189 \r
190   /**\r
191    * \r
192    * @return JarEntry for VamsasArchiveReader.VAMSASXML\r
193    */\r
194   protected ZipEntry getVamsasXmlEntry() {\r
195     return getJarEntry(VAMSASXML);\r
196   }\r
197 \r
198   /**\r
199    * Test for valid vamsas document archive\r
200    * \r
201    * @return true if getVamsasDocumentStream will return a stream likely to\r
202    *         contain valid XML\r
203    */\r
204   public boolean isValid() {\r
205     // TODO: check if VAMSASDOC is well formed (follows\r
206     // www.vamsas.ac.uk/schemas/vamsasDocument.xsd) and all appData references\r
207     // are resolvable - preferably as jar entries\r
208     if (jfile != null) // || jstream!=null)\r
209       return (getVamsasDocumentEntry() != null);\r
210     return false;\r
211   }\r
212 \r
213   protected ZipEntry getAppdataEntry(String AppdataRef) {\r
214     ZipEntry entry;\r
215     if (jfile == null || !isValid()\r
216         || (entry = getJarEntry(AppdataRef)) == null)\r
217       return null;\r
218 \r
219     return entry;\r
220   }\r
221 \r
222   public InputStream getAppdataStream(String AppdataRef) {\r
223     ZipEntry entry = getAppdataEntry(AppdataRef);\r
224     try {\r
225       if (entry != null)\r
226         return getInputStream(entry);\r
227     } catch (IOException e) {\r
228       log.error("Failed when opening AppdataStream for " + AppdataRef, e);\r
229     }\r
230     return null;\r
231   }\r
232 \r
233   /**\r
234    * get the VamsasDocument input stream, if it exists.\r
235    * \r
236    * @return null or valid input stream\r
237    */\r
238   public InputStream getVamsasDocumentStream() {\r
239     InputStream vdoc;\r
240     if (jfile == null || !isValid())\r
241       return null;\r
242     try {\r
243       vdoc = getInputStream(getVamsasDocumentEntry());\r
244     } catch (IOException e) {\r
245       log.error("Whilst geting document stream", e);\r
246       vdoc = null;\r
247     }\r
248     return vdoc;\r
249   }\r
250 \r
251   /**\r
252    * get the VamsasXML input stream, if it exists. Note: Deprecated beyond our\r
253    * prealpha testing.\r
254    * \r
255    * @return null or valid input stream.\r
256    */\r
257 \r
258   public InputStream getVamsasXmlStream() {\r
259     // log.warn("Deprecated call");\r
260     ZipEntry xmle = getVamsasXmlEntry();\r
261     InputStream vdoc;\r
262     if (xmle == null)\r
263       return null;\r
264     try {\r
265       vdoc = getInputStream(xmle);\r
266     } catch (IOException e) {\r
267       log.error("Whilst getting VamsasXmlStream", e);\r
268       vdoc = null;\r
269     }\r
270     return vdoc;\r
271   }\r
272 \r
273   /**\r
274    * silently close the jar file.\r
275    * \r
276    */\r
277   public void close() {\r
278     if (jfile != null) {\r
279       try {\r
280         jfile.close();\r
281         rfile = null;\r
282       } catch (Exception e) {\r
283         log.error("Whilst closing JarFile " + jfileName, e);\r
284       }\r
285     }\r
286   }\r
287 \r
288   /**\r
289    * returns all entries not matching the filespec of a vamsas xml entry\r
290    * \r
291    * @return array of entries.\r
292    */\r
293   public Vector getExtraEntries() {\r
294     if (jfile == null || !isValid())\r
295       return null;\r
296     Vector e = new Vector();\r
297     /*\r
298      * if (jstream!=null) { Enumeration entries = strmentries.keys(); if\r
299      * (entries!=null && entries.hasMoreElements()) { do { JarEntry el =\r
300      * (JarEntry) entries.nextElement(); if (!el.getName().equals(VAMSASDOC) &&\r
301      * !el.getName().equals(VAMSASXML)) e.add(new String(el.getName())); //\r
302      * avoid references } while (entries.hasMoreElements()); } } else\r
303      */\r
304     Enumeration entries = jfile.getEntries();\r
305     if (entries != null && entries.hasMoreElements()) {\r
306       do {\r
307         ZipEntry el = (ZipEntry) entries.nextElement();\r
308         if (!el.getName().equals(VAMSASDOC) && !el.getName().equals(VAMSASXML))\r
309           e.add(new String(el.getName())); // avoid references\r
310       } while (entries.hasMoreElements());\r
311     }\r
312     return e;\r
313   }\r
314 \r
315   /*\r
316    * (non-Javadoc)\r
317    * \r
318    * @see java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)\r
319    */\r
320   private InputStream getInputStream(ZipEntry ze) throws IOException {\r
321     if (jfile != null)\r
322       return jfile.getInputStream(ze);\r
323     return null;\r
324   }\r
325 \r
326   /*\r
327    * (non-Javadoc)\r
328    * \r
329    * @see java.util.jar.JarFile#getJarEntry(java.lang.String)\r
330    */\r
331   private ZipEntry getJarEntry(String name) {\r
332     if (jfile != null)\r
333       return jfile.getEntry(name);\r
334     return null;\r
335   }\r
336 }\r