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