1 package uk.ac.vamsas.client.simpleclient;
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 java.util.jar.JarEntry;
14 import java.util.jar.JarFile;
15 import java.util.jar.JarInputStream;
16 import java.util.jar.JarOutputStream;
17 import java.util.zip.ZipEntry;
18 import java.util.zip.ZipInputStream;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
23 import uk.ac.vamsas.client.AppDataInputStream;
24 import uk.ac.vamsas.objects.utils.document.VersionEntries;
26 * Basic methods for accessing an existing Vamsas Archive,
27 * and Jar entry names for creating new vamsas archives.
32 public class VamsasArchiveReader {
33 private static final int JARFILE_OPEN_RETRIES = 50;
34 private static final int JARFILE_OPEN_RETRYWAIT = 1;
35 private static Log log = LogFactory.getLog(VamsasArchiveReader.class);
37 boolean stream=false; // true if we are seeking on the stream.
38 RandomAccessFile rfile;
39 ZipInputStream jstream=null;
40 Hashtable strmentries = null;
41 private void streamInit() {
42 //throw new Error("VamsasArchiveReader(Stream) Not implemented!");
44 log.debug("Skipping init for Jar Stream input.");
47 strmentries = new Hashtable();
48 log.debug("Jar Stream input Initialisation");
51 // no buffering - we need to be able to move around the random access stream.
52 jstream = new ZipInputStream(new FileInputStream(rfile.getFD())); // no manifest (probably)
53 if (jstream.available()==0)
54 log.warn("Can't read from JarInputStream (Locked stream!)");
58 if ((entry=jstream.getNextEntry())!=null) {
59 if (strmentries.containsKey(entry.getName())) {
60 log.info("Only recording last of duplicate entries '"+entry.getName()+"'");
62 strmentries.put(entry.getName(), new Long(pos++));
65 } while (entry!=null);
68 log.warn("Exceptions during init!",e);
73 public VamsasArchiveReader(File vamsasfile) {
75 int retries=JARFILE_OPEN_RETRIES;
77 if (vamsasfile.exists()) {
78 while (jfile==null && --retries>0)
81 jfile=new JarFile(vamsasfile);
87 Thread.sleep(JARFILE_OPEN_RETRYWAIT);
88 } catch (Exception w) {};
91 if (jfile==null && ex!=null)
93 log.debug("non-serious? Exceptions when opening JarFile at "+vamsasfile,ex);
98 * in an ideal world - this constructor will create a reader object
99 * for the locked file's random access stream.
103 public VamsasArchiveReader(Lock vamsaslock) {
104 // LATER: implement or remove
105 if (vamsaslock==null || !vamsaslock.isLocked())
106 throw new Error("IMPLEMENTATION ERROR: Cannot create a VamsasArchiveReader without a valid lock.");
107 // throw new Error("VamsasArchiveReading from locked IO stream not yet implemented.");
109 rfile = vamsaslock.getRaFile();
110 } catch (Exception e) {
111 log.warn("Unexpected IO Exception when accessing locked vamsas archive stream "+vamsaslock.target,e);
116 throw new Error("Failed to open archive from Locked random access stream.");
120 * the vamsas document version(s) handled by this Reader
122 final public static String DOCUMENT_VERSION=VersionEntries.BETA_VERSION;
124 * name of the jarEntry containing a well formatted vamsas XML Document
127 final public static String VAMSASDOC="vamsasDocument.xml";
130 * name of the jarEntry containing a root VAMSAS element, and containing a
131 * random sequence of VAMSAS DataSet elements
134 final public static String VAMSASXML="vamsas.xml";
136 * seeks jstream to the given entry name and reads it.
140 private JarEntry seekEntry(String entryname) {
143 if (!strmentries.containsKey(entryname))
145 Long entrypos = (Long) strmentries.get(entryname);
146 if (entrypos==null) {
147 log.error("Null entry position for "+entryname);
153 jstream = new ZipInputStream(new FileInputStream(rfile.getFD()));
154 ZipEntry entry = null;
155 long epos = entrypos.longValue();
157 entry = jstream.getNextEntry();
158 } while (entry!=null && --epos>=0);
159 // rfile.seek(entrypos.longValue());
160 // make a Jar entry from a zip entry.
161 return new JarEntry(entry);
163 catch (Exception e) {
164 log.warn("Whilst seeking for "+entryname, e);
170 * @return JarEntry for VamsasArchiveReader.VAMSASDOC
172 protected JarEntry getVamsasDocumentEntry() {
173 return getJarEntry(VAMSASDOC);
177 * @return JarEntry for VamsasArchiveReader.VAMSASXML
179 protected JarEntry getVamsasXmlEntry() {
180 return getJarEntry(VAMSASXML);
183 * Test for valid vamsas document archive
184 * @return true if getVamsasDocumentStream will return a stream likely to contain valid XML
186 public boolean isValid() {
187 // 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
188 if (jfile!=null || jstream!=null)
189 return (getVamsasDocumentEntry()!=null);
194 protected JarEntry getAppdataEntry(String AppdataRef) {
196 if ((jfile==null && jstream==null) || !isValid() || (entry=getJarEntry(AppdataRef))==null)
202 public InputStream getAppdataStream(String AppdataRef) {
203 JarEntry entry=getAppdataEntry(AppdataRef);
206 return getInputStream(entry);
207 } catch (IOException e) {
208 log.error("Failed when opening AppdataStream for "+AppdataRef, e);
213 * get the VamsasDocument input stream, if it exists.
214 * @return null or valid input stream
216 public InputStream getVamsasDocumentStream() {
218 if ((jfile==null && jstream==null) || !isValid())
221 vdoc = getInputStream(getVamsasDocumentEntry());
222 } catch (IOException e) {
223 log.error("Whilst geting document stream",e);
230 * get the VamsasXML input stream, if it exists.
231 * Note: Deprecated beyond our prealpha testing.
232 * @return null or valid input stream.
235 public InputStream getVamsasXmlStream() {
236 // log.warn("Deprecated call");
237 JarEntry xmle=getVamsasXmlEntry();
242 vdoc = getInputStream(xmle);
243 } catch (IOException e) {
244 log.error("Whilst getting VamsasXmlStream",e);
251 * silently close the jar file.
254 public void close() {
258 } catch (IOException e) {
259 log.error("Whilst closing JarFile "+jfile.getName(), e);
264 jstream.closeEntry();
266 // LATER: reference counting for random access file instances is necessary.
268 catch (Exception e) {
269 log.error("Whilst finishing reading from jar input stream",e);
275 * returns all entries not matching the filespec of a vamsas xml entry
276 * @return array of entries.
278 public Vector getExtraEntries() {
279 if ((jfile==null && jstream==null)|| !isValid())
281 Vector e = new Vector();
283 Enumeration entries = strmentries.keys();
284 if (entries!=null && entries.hasMoreElements()) {
286 JarEntry el = (JarEntry) entries.nextElement();
287 if (!el.getName().equals(VAMSASDOC) && !el.getName().equals(VAMSASXML))
288 e.add(new String(el.getName())); // avoid references
289 } while (entries.hasMoreElements());
292 Enumeration entries = jfile.entries();
293 if (entries!=null && entries.hasMoreElements()) {
295 JarEntry el = (JarEntry) entries.nextElement();
296 if (!el.getName().equals(VAMSASDOC) && !el.getName().equals(VAMSASXML))
297 e.add(new String(el.getName())); // avoid references
298 } while (entries.hasMoreElements());
306 * @see java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
308 private InputStream getInputStream(ZipEntry ze) throws IOException {
310 return jfile.getInputStream(ze);
312 seekEntry(ze.getName());
313 return new AppDataInputStream(jstream);
319 * @see java.util.jar.JarFile#getJarEntry(java.lang.String)
321 private JarEntry getJarEntry(String name) {
323 return jfile.getJarEntry(name);
325 return seekEntry(name);