org.jboss.virtual.plugins.context.zip.ZipStreamWrapper Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2006, 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.virtual.plugins.context.zip;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.jboss.logging.Logger;
import org.jboss.virtual.VFSUtils;
/**
* ZipStreamWrapper - for abstracted access to in-memory zip file
*
* @author Marko Strukelj
* @version $Revision: 1.0 $
*/
class ZipStreamWrapper extends ZipBytesWrapper
{
/** Logger */
private static final Logger log = Logger.getLogger(ZipStreamWrapper.class);
/** Is optimizeForMemory turned on */
private static boolean optimizeForMemory;
static
{
optimizeForMemory = AccessController.doPrivileged(new CheckOptimizeForMemory());
if (optimizeForMemory)
log.info("VFS optimizeForMemory is enabled.");
}
/** zip archive - as individual inflated in-memory files */
private Map inMemoryFiles = new LinkedHashMap();
/** size of the zip file composed back from inMemoryFiles */
private int size;
/**
* ZipStreamWrapper is not aware of actual zip source so it can not detect
* if it's been modified, like ZipFileWrapper does.
*
* @param zipStream the current zip stream
* @param name the name
* @param lastModified passed by zip stream provider - constant value
* @throws IOException for any error
*/
ZipStreamWrapper(InputStream zipStream, String name, long lastModified) throws IOException
{
super(zipStream, name, lastModified);
ZipInputStream zis = new ZipInputStream(super.getRootAsStream());
ZipEntry ent = zis.getNextEntry();
while (ent != null)
{
byte [] fileBytes;
if (ent.isDirectory() == false)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
VFSUtils.copyStream(zis, baos);
fileBytes = baos.toByteArray();
ent.setSize(fileBytes.length);
}
else
{
fileBytes = new byte[0];
}
inMemoryFiles.put(ent.getName(), new InMemoryFile(ent, fileBytes));
ent = zis.getNextEntry();
}
if (optimizeForMemory) {
initZipSize();
// we don't need memory buffer any more
super.close();
}
}
InputStream openStream(ZipEntryInfo info) throws IOException
{
// JBVFS-57 JarInputStream composition
if (info.isDirectory())
return recomposeZipAsInputStream(info.getName());
InMemoryFile memFile = inMemoryFiles.get(info.getName());
if (memFile == null)
throw new FileNotFoundException("Failed to find nested jar entry: " + info.getName() + " in zip stream: " + toString());
return new ByteArrayInputStream(memFile.fileBytes);
}
Enumeration entries() throws IOException
{
return new ZipStreamEnumeration();
}
InputStream getRootAsStream() throws FileNotFoundException
{
if (optimizeForMemory)
return recomposeZipAsInputStream();
else
return super.getRootAsStream();
}
long getSize()
{
if (optimizeForMemory)
return size;
else
return super.getSize();
}
void close()
{
inMemoryFiles = null;
super.close();
}
private void initZipSize() throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
recomposeZip(baos);
this.size = baos.size();
}
private void recomposeZip(ByteArrayOutputStream baos) throws IOException
{
recomposeZip(baos, "");
}
protected void recomposeZip(OutputStream baos, String path) throws IOException
{
ZipOutputStream zout = new ZipOutputStream(baos);
zout.setMethod(ZipOutputStream.STORED);
Iterator it = inMemoryFiles.values().iterator();
while(it.hasNext())
{
InMemoryFile memFile = it.next();
ZipEntry oldEntry = memFile.entry;
if (oldEntry.getName().startsWith(path))
{
String newName = oldEntry.getName().substring(path.length());
if(newName.length() == 0)
continue;
ZipEntry newEntry = new ZipEntry(newName);
newEntry.setComment(oldEntry.getComment());
newEntry.setTime(oldEntry.getTime());
newEntry.setSize(oldEntry.getSize());
newEntry.setCrc(oldEntry.getCrc());
zout.putNextEntry(newEntry);
if (oldEntry.isDirectory() == false)
zout.write(memFile.fileBytes);
}
}
zout.close();
}
private InputStream recomposeZipAsInputStream() throws FileNotFoundException
{
return recomposeZipAsInputStream("");
}
static class InMemoryFile
{
ZipEntry entry;
byte [] fileBytes;
public InMemoryFile(ZipEntry entry, byte[] fileBytes)
{
this.entry = entry;
this.fileBytes = fileBytes;
}
}
class ZipStreamEnumeration implements Enumeration
{
private Iterator it;
ZipStreamEnumeration()
{
it = inMemoryFiles.values().iterator();
}
public boolean hasMoreElements()
{
return it.hasNext();
}
public ZipEntry nextElement()
{
return it.next().entry;
}
}
private static class CheckOptimizeForMemory implements PrivilegedAction
{
public Boolean run()
{
String forceString = System.getProperty(VFSUtils.OPTIMIZE_FOR_MEMORY_KEY, "false");
return Boolean.valueOf(forceString);
}
}
}