remove old ebi packages
[vamsas.git] / src / org / vamsas / client / simpleclient / VamsasArchiveReader.java
index 3ca1288..2df47f5 100644 (file)
@@ -3,11 +3,23 @@ package org.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 java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.jar.JarInputStream;
 import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.vamsas.objects.utils.document.VersionEntries;
 /**
  * Basic methods for accessing an existing Vamsas Archive, 
  * and Jar entry names for creating new vamsas archives.
@@ -16,7 +28,44 @@ import java.util.jar.JarOutputStream;
  *
  */
 public class VamsasArchiveReader {
-  JarFile jfile;
+  private static Log log = LogFactory.getLog(VamsasArchiveReader.class);
+  JarFile jfile=null;
+  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;
+    }
+    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;
     if (vamsasfile.exists()) {
@@ -24,13 +73,39 @@ public class VamsasArchiveReader {
         jfile=new JarFile(vamsasfile);
       }
       catch (Exception e) {
+        log.debug("non-serious? couldn't open new JarFile on "+vamsasfile,e);
         jfile=null;
       }
     }
     
   }
+  /**
+   * 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) {
+    // LATER: implement or remove
+    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();
+    } catch (Exception e) {
+      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
    */
   
@@ -42,48 +117,95 @@ public class VamsasArchiveReader {
    */
   
   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 JarEntry getVamsasDocumentEntry() {
-    if (jfile!=null)
-      return jfile.getJarEntry(VAMSASDOC);
-    return null;
+    return getJarEntry(VAMSASDOC);
   }
   /**
    * 
    * @return JarEntry for VamsasArchiveReader.VAMSASXML
    */
   protected JarEntry getVamsasXmlEntry() {
-    if (jfile!=null)
-      return jfile.getJarEntry(VAMSASXML);
-    return null;
+    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() {
-    if (jfile!=null)
-      // 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
+    // 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 JarEntry getAppdataEntry(String AppdataRef) {
+    JarEntry entry;
+    if ((jfile==null && jstream==null) || !isValid() || (entry=getJarEntry(AppdataRef))==null)
+      return null;
+    
+    return entry;
+  }
+  
+  public InputStream getAppdataStream(String AppdataRef) {
+    JarEntry 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())
+    if ((jfile==null && jstream==null) || !isValid())
       return null;
     try {
-      vdoc = jfile.getInputStream(getVamsasDocumentEntry());
+      vdoc = getInputStream(getVamsasDocumentEntry());
     } catch (IOException e) {
-      e.printStackTrace(System.err);
+      log.error("Whilst geting document stream",e);
       vdoc=null;
     }
     return vdoc;
@@ -96,14 +218,15 @@ public class VamsasArchiveReader {
    */
   
   public InputStream getVamsasXmlStream() {
+    // log.warn("Deprecated call");
     JarEntry xmle=getVamsasXmlEntry();
     InputStream vdoc;
     if (xmle==null)
       return null;
     try {
-      vdoc = jfile.getInputStream(xmle);
+      vdoc = getInputStream(xmle);
     } catch (IOException e) {
-      e.printStackTrace(System.err);
+      log.error("Whilst getting VamsasXmlStream",e);
       vdoc=null;
     }
     return vdoc;
@@ -118,8 +241,73 @@ public class VamsasArchiveReader {
       try {
         jfile.close();
       } catch (IOException e) {
-        e.printStackTrace(System.err);
+        log.error("Whilst closing JarFile "+jfile.getName(), e);
+      }
+    }
+    if (jstream!=null) {
+      try {
+        jstream.closeEntry();
+        jstream=null;
+        // LATER: reference counting for random access file instances is necessary.
+      }
+      catch (Exception e) {
+        log.error("Whilst finishing reading from jar input stream",e);
+      }
+    }
+  }
+  
+  /**
+   * returns all entries not matching the filespec of a vamsas xml entry
+   * @return array of entries.
+   */
+  public Vector getExtraEntries() {
+    if ((jfile==null && jstream==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.entries();
+      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());
+      }
+      return e;
+    }
+    return null;
+  }
+  
+  /* (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);
+    if (jstream!=null) {
+      seekEntry(ze.getName());
+      return new AppDataInputStream(jstream);
+    }
+    return null;
+  }
+    
+    /* (non-Javadoc)
+     * @see java.util.jar.JarFile#getJarEntry(java.lang.String)
+     */
+    private JarEntry getJarEntry(String name) {
+      if (jfile!=null)
+        return jfile.getJarEntry(name);
+      if (jstream!=null)
+        return seekEntry(name);
+      return null;
     }
   }
-}