[jboss-cvs] JBossAS SVN: r103536 - in projects/vfs/trunk/src: test/java/org/jboss/test/vfs and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Apr 5 12:12:53 EDT 2010


Author: johnbailey
Date: 2010-04-05 12:12:52 -0400 (Mon, 05 Apr 2010)
New Revision: 103536

Added:
   projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarFileInputStream.java
   projects/vfs/trunk/src/test/java/org/jboss/test/vfs/VirtualJarFileInputStreamTest.java
Modified:
   projects/vfs/trunk/src/main/java/org/jboss/vfs/VFSUtils.java
   projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarInputStream.java
   projects/vfs/trunk/src/test/java/org/jboss/test/vfs/AbstractVFSTest.java
Log:
[JBVFS-155] - A virtual jar file input stream support

Modified: projects/vfs/trunk/src/main/java/org/jboss/vfs/VFSUtils.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/vfs/VFSUtils.java	2010-04-05 13:47:10 UTC (rev 103535)
+++ projects/vfs/trunk/src/main/java/org/jboss/vfs/VFSUtils.java	2010-04-05 16:12:52 UTC (rev 103536)
@@ -43,6 +43,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
@@ -760,7 +761,43 @@
         return EMPTY_STREAM;
     }
 
+
     /**
+     * Get an input stream that will always be consumable as a Zip/Jar file.  The input stream will not be an instance
+     * of a JarInputStream, but will stream bytes according to the Zip specification.  Using this method, a VFS file
+     * or directory can be written to disk as a normal jar/zip file.
+     *
+     * @param virtualFile The virtual to get a jar file input stream for
+     * @return An input stream returning bytes according to the zip spec
+     * @throws IOException if any problems occur
+     */
+    public static InputStream createJarFileInputStream(final VirtualFile virtualFile) throws IOException {
+        if(virtualFile.isDirectory()) {
+            final VirtualJarInputStream jarInputStream = new VirtualJarInputStream(virtualFile);
+            return new VirtualJarFileInputStream(jarInputStream);
+        }
+        InputStream inputStream = null;
+        try {
+            final byte[] expectedHeader = new byte[4];
+
+            expectedHeader[0] = (byte) (JarEntry.LOCSIG & 0xff);
+            expectedHeader[1] = (byte) ((JarEntry.LOCSIG >>> 8) & 0xff);
+            expectedHeader[2] = (byte) ((JarEntry.LOCSIG >>> 16) & 0xff);
+            expectedHeader[3] = (byte) ((JarEntry.LOCSIG >>> 24) & 0xff);
+
+            inputStream = virtualFile.openStream();
+            final byte[] bytes = new byte[4];
+            final int read = inputStream.read(bytes, 0, 4);
+            if(read < 4 || !Arrays.equals(expectedHeader, bytes)) {
+                throw new IOException("Invalid jar signature " + Arrays.toString(bytes) +" should be " + Arrays.toString(expectedHeader));
+            }
+        } finally {
+            safeClose(inputStream);
+        }
+        return virtualFile.openStream();
+    }
+
+    /**
      * Expand a zip file to a destination directory.  The directory must exist.  If an error occurs, the destination
      * directory may contain a partially-extracted archive, so cleanup is up to the caller.
      *

Added: projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarFileInputStream.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarFileInputStream.java	                        (rev 0)
+++ projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarFileInputStream.java	2010-04-05 16:12:52 UTC (rev 103536)
@@ -0,0 +1,431 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.vfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+
+/**
+ * An input stream that can be used to wrap an VirtualJarInputStream (so any VFS dir)
+ * and produce a byte stream following the Zip standard.
+ *
+ * @author <a href="mailto:jbailey at redhat.com">John Bailey</a>
+ */
+public class VirtualJarFileInputStream extends InputStream {
+    // Needs to be sufficiently sized to allow local and central file headers with a single entry name
+    private static final int MINIMUM_BUFFER_LENGTH = 1024;
+
+    private final VirtualJarInputStream virtualJarInputStream;
+
+    private State currentState = State.NOT_STARTED;
+
+    private final List<ProcessedEntry> processedEntries = new LinkedList<ProcessedEntry>();
+    private ProcessedEntry currentEntry;
+
+    private final ByteBuffer buffer;
+    private final CRC32 crc = new CRC32();
+
+    private int currentCentralEntryIdx;
+    private long centralOffset;
+    private long totalRead;
+
+    /**
+     * Create with the minimum put length
+     *
+     * @param virtualJarInputStream The virtual jar input stream to base the stream off of
+     */
+    public VirtualJarFileInputStream(final VirtualJarInputStream virtualJarInputStream) {
+        this(virtualJarInputStream, MINIMUM_BUFFER_LENGTH);
+    }
+
+    /**
+     * Create with the a specified put size
+     *
+     * @param virtualJarInputStream The virtual jar input stream to base the stream off of
+     * @param bufferLength          The length of put to use
+     */
+    public VirtualJarFileInputStream(final VirtualJarInputStream virtualJarInputStream, int bufferLength) {
+        if (virtualJarInputStream == null) throw new IllegalArgumentException("virtualJarInputStream is required");
+        if (bufferLength < MINIMUM_BUFFER_LENGTH)
+            throw new IllegalArgumentException("The totalBufferLength must be larger than " + MINIMUM_BUFFER_LENGTH);
+
+        this.virtualJarInputStream = virtualJarInputStream;
+
+        buffer = new ByteBuffer(bufferLength);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int read() throws IOException {
+        int readByte = -1;
+        while (currentState != null && (readByte = currentState.read(this)) == -1) {
+            currentState = currentState.getNextState(this);
+        }
+        totalRead++;
+        return readByte;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close() throws IOException {
+        VFSUtils.safeClose(virtualJarInputStream);
+        super.close();
+    }
+
+    /**
+     * Close the current entry, and calculate the crc value.
+     *
+     * @throws IOException if any problems occur
+     */
+    private void closeCurrent() throws IOException {
+        virtualJarInputStream.closeEntry();
+        currentEntry.crc = crc.getValue();
+        crc.reset();
+    }
+
+    /**
+     * Buffer the content of the local file header for a single entry.
+     *
+     * @return true if the next local file header was buffered
+     * @throws IOException if any problems occur
+     */
+    private boolean bufferLocalFileHeader() throws IOException {
+        buffer.reset();
+        JarEntry jarEntry = virtualJarInputStream.getNextJarEntry();
+
+        if (jarEntry == null)
+            return false;
+
+        currentEntry = new ProcessedEntry(jarEntry, totalRead);
+        processedEntries.add(currentEntry);
+
+
+        bufferInt(ZipEntry.LOCSIG);    // Local file header signature
+        bufferShort(10);               // Extraction version
+        bufferShort(0);                // Flags
+        bufferShort(ZipEntry.STORED);  // Compression type
+        bufferInt(jarEntry.getTime()); // Entry time
+        bufferInt(0);                  // CRC
+        bufferInt(0);                  // Compressed size
+        bufferInt(0);                  // Uncompressed size
+        byte[] nameBytes = jarEntry.getName().getBytes("UTF8");
+        bufferShort(nameBytes.length); // Entry name length
+        bufferShort(0);                // Extra length
+        buffer(nameBytes);
+        return true;
+    }
+
+    /**
+     * Buffer the central file header record for a single entry.
+     *
+     * @return true if the next central file header was buffered
+     * @throws IOException if any problems occur
+     */
+    private boolean bufferNextCentralFileHeader() throws IOException {
+        buffer.reset();
+
+        if (currentCentralEntryIdx == processedEntries.size())
+            return false;
+
+        ProcessedEntry entry = processedEntries.get(currentCentralEntryIdx++);
+
+        JarEntry jarEntry = entry.jarEntry;
+        bufferInt(ZipEntry.CENSIG);       // Central file header signature
+        bufferShort(10);                  // Version made by
+        bufferShort(10);                  // Extraction version
+        bufferShort(0);                   // Flags
+        bufferShort(ZipEntry.STORED);     // Compression type
+        bufferInt(jarEntry.getTime());    // Entry time
+        bufferInt(entry.crc);             // CRC
+        bufferInt(jarEntry.getSize());    // Compressed size
+        bufferInt(jarEntry.getSize());    // Uncompressed size
+        byte[] nameBytes = jarEntry.getName().getBytes("UTF8");
+        bufferShort(nameBytes.length);    // Entry name length
+        bufferShort(0);                   // Extra field length
+        bufferShort(0);                   // File comment length
+        bufferShort(0);                   // Disk number start
+        bufferShort(0);                   // Internal file attributes
+        bufferInt(0);                     // External file attributes
+        bufferInt(entry.offset);          // Relative offset of local header
+        buffer(nameBytes);
+        return true;
+    }
+
+        /**
+     * Write the central file header records.  This is repeated
+     * until all entries have been added to the central file header.
+     *
+     * @throws IOException if any problem occur
+     */
+    private void bufferCentralDirectoryEnd() throws IOException {
+        buffer.reset();
+        long lengthOfCentral = totalRead - centralOffset;
+
+        int count = processedEntries.size();
+        bufferInt(JarEntry.ENDSIG);      // End of central directory signature
+        bufferShort(0);                  // Number of this disk
+        bufferShort(0);                  // Start of central directory disk
+        bufferShort(count);              // Number of processedEntries on disk
+        bufferShort(count);              // Total number of processedEntries
+        bufferInt(lengthOfCentral);      // Size of central directory
+        bufferInt(centralOffset);        // Offset of start of central directory
+        bufferShort(0);                  // Comment Length
+    }
+
+    /**
+     * Buffer a 32-bit integer in little-endian
+     *
+     * @param i A long representation of a 32 bit int
+     */
+    private void bufferInt(long i) {
+        buffer((byte) (i & 0xff));
+        buffer((byte) ((i >>> 8) & 0xff));
+        buffer((byte) ((i >>> 16) & 0xff));
+        buffer((byte) ((i >>> 24) & 0xff));
+    }
+
+    /**
+     * Buffer a 16-bit short in little-endian
+     *
+     * @param i An int representation of a 16 bit short
+     */
+    private void bufferShort(int i) {
+        buffer((byte) (i & 0xff));
+        buffer((byte) ((i >>> 8) & 0xff));
+    }
+
+    /**
+     * Buffer a single byte
+     *
+     * @param b The byte
+     */
+    private void buffer(byte b) {
+        if(buffer.hasCapacity())
+            buffer.put(b);
+        else
+            throw new IllegalStateException("Buffer does not have enough capacity");
+    }
+
+    /**
+     * Buffer a byte array
+     *
+     * @param bytes The bytes
+     */
+    private void buffer(byte[] bytes) {
+        for (byte b : bytes)
+            buffer(b);
+    }
+
+
+    private class ProcessedEntry {
+        private final JarEntry jarEntry;
+        private final long offset;
+        private long crc;
+
+        private ProcessedEntry(final JarEntry jarEntry, final long offset) {
+            this.jarEntry = jarEntry;
+            this.offset = offset;
+        }
+    }
+
+    /**
+     * Basic state machine that will allow the process to transition between the different process states.
+     *
+     * The following describes the process flow:
+     * [NOT_STARTED] - Initial state
+     * - Does not provide content
+     * - Transitions [LOCAL_ENTRY_HEADER]
+     * [LOCAL_ENTRY_HEADER] - The phase for reading the Local Directory Header
+     * - Provides content of the local directory header by populating and feeding off a buffer
+     * - Transitions to [ENTRY_CONTENT] if the header was written
+     * - Transitions to [START_CENTRAL_DIRECTORY] if this is the last local entry header
+     * [ENTRY_CONTENT] - The phase for reading the content of an entry
+     * - Provides content of the entry using the VirtualJarInputStream
+     * - Transitions to [LOCAL_ENTRY_HEADER]
+     * [START_CENTRAL_DIRECTORY] - Phased used to transition into the central directory
+     * - Does not provide content
+     * - Transitions to [CENTRAL_ENTRY_HEADER]
+     * [CENTRAL_ENTRY_HEADER] - The phase for reading the content of a single central directory header
+     * - Provides content for the central directory header by feeding off a buffer
+     * - Transitions to [CENTRAL_ENTRY_HEADER]
+     * - Transitions to [CENTRAL_END] if there are no more entries
+     * [CENTRAL_END] - The phase for reading the contents of the central directory end
+     * - Provides content for central directory end by feeing off a buffer
+     * - Transitions to NULL to terminate the processing
+     */
+    private enum State {
+        NOT_STARTED {
+            @Override
+            State transition(VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                return LOCAL_ENTRY_HEADER;
+            }
+        },
+        LOCAL_ENTRY_HEADER {
+            boolean buffered;
+            @Override
+            void init(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                buffered = jarFileInputStream.bufferLocalFileHeader();
+            }
+
+            @Override
+            int read(VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                final ByteBuffer buffer = jarFileInputStream.buffer;
+                if (buffered && buffer.hasRemaining())
+                    return buffer.get();
+                return -1;
+            }
+
+            @Override
+            State transition(final VirtualJarFileInputStream virtualJarFileInputStream) throws IOException {
+                if (buffered)
+                    return ENTRY_CONTENT;
+                return START_CENTRAL_DIRECTORY;
+            }
+        },
+        ENTRY_CONTENT {
+
+            @Override
+            int read(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                final VirtualJarInputStream virtualJarInputStream = jarFileInputStream.virtualJarInputStream;
+                return virtualJarInputStream.read();
+            }
+            @Override
+            State transition(final VirtualJarFileInputStream virtualJarFileInputStream) throws IOException {
+                virtualJarFileInputStream.closeCurrent();
+                return LOCAL_ENTRY_HEADER;
+            }
+        },
+        START_CENTRAL_DIRECTORY {
+            @Override
+            void init(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                jarFileInputStream.centralOffset = jarFileInputStream.totalRead;
+            }
+
+            @Override
+            State transition(final VirtualJarFileInputStream virtualJarFileInputStream) throws IOException {
+                return CENTRAL_ENTRY_HEADER;
+            }
+        },
+        CENTRAL_ENTRY_HEADER {
+            boolean buffered;
+            @Override
+            void init(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                buffered = jarFileInputStream.bufferNextCentralFileHeader();
+            }
+
+            @Override
+            int read(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                final ByteBuffer buffer = jarFileInputStream.buffer;
+                if (buffered && buffer.hasRemaining())
+                    return buffer.get();
+                return -1;
+            }
+            @Override
+            State transition(final VirtualJarFileInputStream virtualJarFileInputStream) throws IOException {
+                if (buffered)
+                    return CENTRAL_ENTRY_HEADER;
+                return CENTRAL_END;
+            }
+        },
+        CENTRAL_END {
+            @Override
+            void init(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                jarFileInputStream.bufferCentralDirectoryEnd();
+            }
+
+            @Override
+            int read(final VirtualJarFileInputStream jarFileInputStream) throws IOException {
+                final ByteBuffer buffer = jarFileInputStream.buffer;
+                if (buffer.hasRemaining())
+                    return buffer.get();
+                return -1;
+            }
+
+            @Override
+            State transition(final VirtualJarFileInputStream virtualJarFileInputStream) throws IOException {
+                return null;
+            }
+        };
+
+
+        void init(VirtualJarFileInputStream jarFileInputStream) throws IOException {
+        }
+
+        abstract State transition(VirtualJarFileInputStream virtualJarFileInputStream) throws IOException;
+
+        int read(VirtualJarFileInputStream jarFileInputStream) throws IOException {
+            return -1;
+        }
+
+        State getNextState(VirtualJarFileInputStream jarFileInputStream) throws IOException {
+            State nextState = transition(jarFileInputStream);
+            if (nextState != null)
+                nextState.init(jarFileInputStream);
+            return nextState;
+        }
+    }
+
+
+    private static class ByteBuffer {
+
+        private final int bufferLength;
+        private final byte[] buffer;
+        private int bufferPosition;
+        private int bufferDepth;
+
+        private ByteBuffer(final int bufferLength) {
+            this.buffer = new byte[bufferLength];
+            this.bufferLength = bufferLength;
+        }
+
+        private boolean hasRemaining() {
+            return bufferPosition < bufferDepth;
+        }
+
+        private boolean hasCapacity() {
+            return bufferDepth < bufferLength;
+        }
+
+        private byte get() {
+            return buffer[bufferPosition++];
+        }
+
+        private void put(byte b) {
+            buffer[bufferDepth++] = b;
+        }
+
+        private void reset() {
+            bufferPosition = 0;
+            bufferDepth = 0;
+        }
+    }
+}

Modified: projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarInputStream.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarInputStream.java	2010-04-05 13:47:10 UTC (rev 103535)
+++ projects/vfs/trunk/src/main/java/org/jboss/vfs/VirtualJarInputStream.java	2010-04-05 16:12:52 UTC (rev 103536)
@@ -267,6 +267,12 @@
          return virtualFile.getSize();
       }
 
+      @Override
+      public long getTime()
+      {
+         return virtualFile.getLastModified();
+      }
+
       /** {@inheritDoc} **/
       @Override
       public boolean isDirectory() {

Modified: projects/vfs/trunk/src/test/java/org/jboss/test/vfs/AbstractVFSTest.java
===================================================================
--- projects/vfs/trunk/src/test/java/org/jboss/test/vfs/AbstractVFSTest.java	2010-04-05 13:47:10 UTC (rev 103535)
+++ projects/vfs/trunk/src/test/java/org/jboss/test/vfs/AbstractVFSTest.java	2010-04-05 16:12:52 UTC (rev 103536)
@@ -121,6 +121,10 @@
 
    protected byte[] getContent(VirtualFile virtualFile) throws IOException {
       InputStream is = virtualFile.openStream();
+      return getContent(is);
+   }
+
+   protected byte[] getContent(InputStream is) throws IOException {
       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       VFSUtils.copyStreamAndClose(is, bos);
       return bos.toByteArray();

Added: projects/vfs/trunk/src/test/java/org/jboss/test/vfs/VirtualJarFileInputStreamTest.java
===================================================================
--- projects/vfs/trunk/src/test/java/org/jboss/test/vfs/VirtualJarFileInputStreamTest.java	                        (rev 0)
+++ projects/vfs/trunk/src/test/java/org/jboss/test/vfs/VirtualJarFileInputStreamTest.java	2010-04-05 16:12:52 UTC (rev 103536)
@@ -0,0 +1,121 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.vfs;
+
+import org.jboss.vfs.*;
+import org.jboss.vfs.VirtualJarFileInputStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * @author <a href="mailto:jbailey at redhat.com">John Bailey</a>
+ */
+public class VirtualJarFileInputStreamTest extends AbstractVFSTest {
+
+    public VirtualJarFileInputStreamTest(final String name) {
+        super(name);
+    }
+
+
+    public void testDirectoryStream() throws Exception {
+        VirtualFile testDir = getVirtualFile("/vfs/test/jar1");
+
+        InputStream inputStream = VFSUtils.createJarFileInputStream(testDir);
+
+        TempDir tempDir = provider.createTempDir("test");
+
+        File tempFile = tempDir.getFile("test.zip");
+
+        VFSUtils.copyStreamAndClose(inputStream, new FileOutputStream(tempFile));
+
+        JarFile jarFile = new JarFile(tempFile);
+
+        assertEntryContent("META-INF/MANIFEST.MF", jarFile, testDir);
+        assertEntry("org/", jarFile);
+        assertEntry("org/jboss/", jarFile);
+        assertEntry("org/jboss/test/", jarFile);
+        assertEntry("org/jboss/test/vfs/", jarFile);
+        assertEntry("org/jboss/test/vfs/support/", jarFile);
+        assertEntry("org/jboss/test/vfs/support/jar1/", jarFile);
+        assertEntryContent("org/jboss/test/vfs/support/jar1/ClassInJar1$InnerClass.class", jarFile, testDir);
+        assertEntryContent("org/jboss/test/vfs/support/jar1/ClassInJar1.class", jarFile, testDir);
+    }
+
+    public void testFileStream() throws Exception {
+        VirtualFile testJar = getVirtualFile("/vfs/test/jar1.jar");
+
+        InputStream inputStream = VFSUtils.createJarFileInputStream(testJar);
+
+        TempDir tempDir = provider.createTempDir("test");
+
+        File tempFile = tempDir.getFile("test.zip");
+
+        VFSUtils.copyStreamAndClose(inputStream, new FileOutputStream(tempFile));
+
+        JarFile jarFile = new JarFile(tempFile);
+
+        assertEntry("META-INF/MANIFEST.MF", jarFile);
+        assertEntry("org/", jarFile);
+        assertEntry("org/jboss/", jarFile);
+        assertEntry("org/jboss/test/", jarFile);
+        assertEntry("org/jboss/test/vfs/", jarFile);
+        assertEntry("org/jboss/test/vfs/support/", jarFile);
+        assertEntry("org/jboss/test/vfs/support/jar1/", jarFile);
+        assertEntry("org/jboss/test/vfs/support/jar1/ClassInJar1$InnerClass.class", jarFile);
+        assertEntry("org/jboss/test/vfs/support/jar1/ClassInJar1.class", jarFile);
+    }
+
+    public void testInvalidFileStream() throws Exception {
+        VirtualFile testJar = getVirtualFile("/vfs/test/filesonly.mf");
+        try {
+            VFSUtils.createJarFileInputStream(testJar);
+            fail("Should have thrown IOException");
+        } catch (IOException expected) {
+            assertTrue(expected.getMessage().startsWith("Invalid jar signature"));
+        }
+
+    }
+
+    private void assertEntry(String name, JarFile jarFile) throws Exception {
+        JarEntry entry = jarFile.getJarEntry(name);
+        assertNotNull(entry);
+    }
+
+    private void assertEntryContent(String name, JarFile jarFile, VirtualFile parent) throws Exception {
+        JarEntry entry = jarFile.getJarEntry(name);
+        assertNotNull(entry);
+        InputStream entryStream = jarFile.getInputStream(entry);
+        InputStream fileStream = parent.getChild(name).openStream();
+        assertContentEqual(fileStream, entryStream);
+    }
+
+    private void assertContentEqual(InputStream in, InputStream other) throws Exception {
+        assertArrayEquals(getContent(in), getContent(other));
+    }
+}




More information about the jboss-cvs-commits mailing list