package uk.ac.vamsas.client.simpleclient; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.RandomAccessFile; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import org.apache.tools.zip.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import uk.ac.vamsas.client.AppDataInputStream; import uk.ac.vamsas.objects.utils.document.VersionEntries; /** * Basic methods for accessing an existing Vamsas Archive, * and Jar entry names for creating new vamsas archives. * * @author jimp * */ public class VamsasArchiveReader { private static final int JARFILE_OPEN_RETRIES = 50; private static final int JARFILE_OPEN_RETRYWAIT = 1; private static Log log = LogFactory.getLog(VamsasArchiveReader.class); ZipFile jfile=null; String jfileName="randomAccessFile"; boolean stream=false; // true if we are seeking on the stream. RandomAccessFile rfile; // ZipInputStream jstream=null; Hashtable strmentries = null; private void streamInit() { //throw new Error("VamsasArchiveReader(Stream) Not implemented!"); if (!stream) { log.debug("Skipping init for Jar Stream input."); return; } else { throw new Error("Implementation error - we don't do streams - only files or RA files"); } /*strmentries = new Hashtable(); log.debug("Jar Stream input Initialisation"); try { rfile.seek(0); // no buffering - we need to be able to move around the random access stream. jstream = new ZipInputStream(new FileInputStream(rfile.getFD())); // no manifest (probably) if (jstream.available()==0) log.warn("Can't read from JarInputStream (Locked stream!)"); ZipEntry entry=null; long pos=0; do { if ((entry=jstream.getNextEntry())!=null) { if (strmentries.containsKey(entry.getName())) { log.info("Only recording last of duplicate entries '"+entry.getName()+"'"); } strmentries.put(entry.getName(), new Long(pos++)); jstream.closeEntry(); } } while (entry!=null); } catch (Exception e) { log.warn("Exceptions during init!",e); jstream=null; } */ } public VamsasArchiveReader(File vamsasfile) { jfile=null; int retries=JARFILE_OPEN_RETRIES; Exception ex=null; if (vamsasfile.exists()) { while (jfile==null && --retries>0) { try { jfile=new ZipFile(vamsasfile); jfileName = vamsasfile.toString(); } catch (Exception e) { ex = e; jfile=null; try { Thread.sleep(JARFILE_OPEN_RETRYWAIT); } catch (Exception w) {}; } } if (jfile==null && ex!=null) { log.debug("non-serious? Exceptions when opening JarFile at "+vamsasfile,ex); } } } /** * in an ideal world - this constructor will create a reader object * for the locked file's random access stream. * * @param vamsaslock */ public VamsasArchiveReader(Lock vamsaslock) { jfile = null; if (vamsaslock==null || !vamsaslock.isLocked()) throw new Error("IMPLEMENTATION ERROR: Cannot create a VamsasArchiveReader without a valid lock."); // throw new Error("VamsasArchiveReading from locked IO stream not yet implemented."); try { rfile = vamsaslock.getRaFile(); jfile = new ZipFile(rfile); if (vamsaslock.target!=null) jfileName = vamsaslock.target.toString(); } catch (Exception e) { rfile = null; jfile = null; log.warn("Unexpected IO Exception when accessing locked vamsas archive stream "+vamsaslock.target,e); } /*stream = true; streamInit(); if (jstream==null) throw new Error("Failed to open archive from Locked random access stream."); */ } /** * the vamsas document version(s) handled by this Reader */ final public static String DOCUMENT_VERSION=VersionEntries.BETA_VERSION; /** * name of the jarEntry containing a well formatted vamsas XML Document */ final public static String VAMSASDOC="vamsasDocument.xml"; /** * name of the jarEntry containing a root VAMSAS element, and containing a * random sequence of VAMSAS DataSet elements */ final public static String VAMSASXML="vamsas.xml"; /** * seeks jstream to the given entry name and reads it. * @param entryname * @return private JarEntry seekEntry(String entryname) { if (jstream==null) return null; if (!strmentries.containsKey(entryname)) return null; Long entrypos = (Long) strmentries.get(entryname); if (entrypos==null) { log.error("Null entry position for "+entryname); return null; } try { jstream=null; rfile.seek(0); jstream = new ZipInputStream(new FileInputStream(rfile.getFD())); ZipEntry entry = null; long epos = entrypos.longValue(); do { entry = jstream.getNextEntry(); } while (entry!=null && --epos>=0); // rfile.seek(entrypos.longValue()); // make a Jar entry from a zip entry. return new JarEntry(entry); } catch (Exception e) { log.warn("Whilst seeking for "+entryname, e); } return null; } */ /** * * @return JarEntry for VamsasArchiveReader.VAMSASDOC */ protected ZipEntry getVamsasDocumentEntry() { return getJarEntry(VAMSASDOC); } /** * * @return JarEntry for VamsasArchiveReader.VAMSASXML */ protected ZipEntry getVamsasXmlEntry() { return getJarEntry(VAMSASXML); } /** * Test for valid vamsas document archive * @return true if getVamsasDocumentStream will return a stream likely to contain valid XML */ public boolean isValid() { // 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 if (jfile!=null) // || jstream!=null) return (getVamsasDocumentEntry()!=null); return false; } protected ZipEntry getAppdataEntry(String AppdataRef) { ZipEntry entry; if (jfile==null || !isValid() || (entry=getJarEntry(AppdataRef))==null) return null; return entry; } public InputStream getAppdataStream(String AppdataRef) { ZipEntry entry=getAppdataEntry(AppdataRef); try { if (entry!=null) return getInputStream(entry); } catch (IOException e) { log.error("Failed when opening AppdataStream for "+AppdataRef, e); } return null; } /** * get the VamsasDocument input stream, if it exists. * @return null or valid input stream */ public InputStream getVamsasDocumentStream() { InputStream vdoc; if (jfile==null || !isValid()) return null; try { vdoc = getInputStream(getVamsasDocumentEntry()); } catch (IOException e) { log.error("Whilst geting document stream",e); vdoc=null; } return vdoc; } /** * get the VamsasXML input stream, if it exists. * Note: Deprecated beyond our prealpha testing. * @return null or valid input stream. */ public InputStream getVamsasXmlStream() { // log.warn("Deprecated call"); ZipEntry xmle=getVamsasXmlEntry(); InputStream vdoc; if (xmle==null) return null; try { vdoc = getInputStream(xmle); } catch (IOException e) { log.error("Whilst getting VamsasXmlStream",e); vdoc=null; } return vdoc; } /** * silently close the jar file. * */ public void close() { if (jfile!=null) { try { jfile.close(); rfile=null; } catch (Exception e) { log.error("Whilst closing JarFile "+jfileName, e); } } } /** * returns all entries not matching the filespec of a vamsas xml entry * @return array of entries. */ public Vector getExtraEntries() { if (jfile==null || !isValid()) return null; Vector e = new Vector(); /*if (jstream!=null) { Enumeration entries = strmentries.keys(); if (entries!=null && entries.hasMoreElements()) { do { JarEntry el = (JarEntry) entries.nextElement(); if (!el.getName().equals(VAMSASDOC) && !el.getName().equals(VAMSASXML)) e.add(new String(el.getName())); // avoid references } while (entries.hasMoreElements()); } } else */ Enumeration entries = jfile.getEntries(); if (entries!=null && entries.hasMoreElements()) { do { ZipEntry el = (ZipEntry) entries.nextElement(); if (!el.getName().equals(VAMSASDOC) && !el.getName().equals(VAMSASXML)) e.add(new String(el.getName())); // avoid references } while (entries.hasMoreElements()); } return e; } /* (non-Javadoc) * @see java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) */ private InputStream getInputStream(ZipEntry ze) throws IOException { if (jfile!=null) return jfile.getInputStream(ze); return null; } /* (non-Javadoc) * @see java.util.jar.JarFile#getJarEntry(java.lang.String) */ private ZipEntry getJarEntry(String name) { if (jfile!=null) return jfile.getEntry(name); return null; } }