Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jboss.vfs.spi.JavaZipFileSystem Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2009, JBoss Inc., and individual contributors as indicated
* by the @authors tag.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.vfs.spi;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.CodeSigner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.jboss.vfs.TempDir;
import org.jboss.vfs.VFSLogger;
import org.jboss.vfs.VFSMessages;
import org.jboss.vfs.VFSUtils;
import org.jboss.vfs.VirtualFile;
import org.jboss.vfs.util.PathTokenizer;
/**
* {@inheritDoc}
*
* This implementation is backed by a zip file. The provided file must be owned by this instance; otherwise, if the
* file disappears unexpectedly, the filesystem will malfunction.
*
* @author David M. Lloyd
* @author Ales Justin
*/
public final class JavaZipFileSystem implements FileSystem {
private final JarFile zipFile;
private final File archiveFile;
private final long zipTime;
private final ZipNode rootNode;
private final TempDir tempDir;
private final File contentsDir;
/**
* Create a new instance.
*
* @param name the name of the source archive
* @param inputStream an input stream from the source archive
* @param tempDir the temp dir into which zip information is stored
* @throws java.io.IOException if an I/O error occurs
*/
public JavaZipFileSystem(String name, InputStream inputStream, TempDir tempDir) throws IOException {
this(tempDir.createFile(name, inputStream), tempDir);
}
/**
* Create a new instance.
*
* @param archiveFile the original archive file
* @param tempDir the temp dir into which zip information is stored
* @throws java.io.IOException if an I/O error occurs
*/
public JavaZipFileSystem(File archiveFile, TempDir tempDir) throws IOException {
zipTime = archiveFile.lastModified();
final JarFile zipFile;
this.zipFile = zipFile = new JarFile(archiveFile);
this.archiveFile = archiveFile;
this.tempDir = tempDir;
final Enumeration extends JarEntry> entries = zipFile.entries();
final ZipNode rootNode = new ZipNode(new HashMap(), "", null);
FILES:
for (JarEntry entry : iter(entries)) {
final String name = entry.getName();
final boolean isDirectory = entry.isDirectory();
final List tokens = PathTokenizer.getTokens(name);
ZipNode node = rootNode;
final Iterator it = tokens.iterator();
while (it.hasNext()) {
String token = it.next();
if (PathTokenizer.isCurrentToken(token) || PathTokenizer.isReverseToken(token)) {
// invalid file name
continue FILES;
}
final Map children = node.children;
if (children == null) {
// todo - log bad zip entry
continue FILES;
}
ZipNode child = children.get(token);
if (child == null) {
child = it.hasNext() || isDirectory ? new ZipNode(new HashMap(), token, null) : new ZipNode(null, token, entry);
children.put(token, child);
}
node = child;
}
}
this.rootNode = rootNode;
contentsDir = tempDir.getFile("contents");
contentsDir.mkdir();
VFSLogger.ROOT_LOGGER.tracef("Created zip filesystem for file %s in temp dir %s", archiveFile, tempDir);
}
/**
* {@inheritDoc}
*/
private static Iterable iter(final Enumeration entries) {
return new EnumerationIterable(entries);
}
/**
* {@inheritDoc}
*/
public File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException {
final ZipNode zipNode = getExistingZipNode(mountPoint, target);
// check if we have cached one already
File cachedFile = zipNode.cachedFile;
if (cachedFile != null) {
return cachedFile;
}
synchronized (zipNode) {
// double-check
cachedFile = zipNode.cachedFile;
if (cachedFile != null) {
return cachedFile;
}
// nope, create a cached temp
final JarEntry zipEntry = zipNode.entry;
String name = target.getPathNameRelativeTo(mountPoint);
cachedFile = buildFile(contentsDir, name);
if (zipEntry == null) {
cachedFile.mkdir();
} else {
VFSUtils.copyStreamAndClose(zipFile.getInputStream(zipEntry), new BufferedOutputStream(new FileOutputStream(cachedFile)));
}
zipNode.cachedFile = cachedFile;
return cachedFile;
}
}
/**
* {@inheritDoc}
*/
public InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException {
final ZipNode zipNode = getExistingZipNode(mountPoint, target);
final File cachedFile = zipNode.cachedFile;
if (cachedFile != null) {
return new FileInputStream(cachedFile);
}
if (rootNode == zipNode) {
return new FileInputStream(archiveFile);
}
final JarEntry entry = zipNode.entry;
if (entry == null) {
throw VFSMessages.MESSAGES.notAFile(target.getPathName());
}
return zipFile.getInputStream(entry);
}
/**
* {@inheritDoc}
*/
public boolean delete(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = getZipNode(mountPoint, target);
if (zipNode == null) {
return false;
}
final File cachedFile = zipNode.cachedFile;
return cachedFile != null && cachedFile.delete();
}
/**
* {@inheritDoc}
*/
public long getSize(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = getZipNode(mountPoint, target);
if (zipNode == null) {
return 0L;
}
final File cachedFile = zipNode.cachedFile;
final JarEntry entry = zipNode.entry;
if (zipNode == rootNode) {
return archiveFile.length();
}
return cachedFile != null ? cachedFile.length() : entry == null ? 0L : entry.getSize();
}
/**
* {@inheritDoc}
*/
public long getLastModified(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = getZipNode(mountPoint, target);
if (zipNode == null) {
return 0L;
}
final File cachedFile = zipNode.cachedFile;
final JarEntry entry = zipNode.entry;
return cachedFile != null ? cachedFile.lastModified() : entry == null ? zipTime : entry.getTime();
}
/**
* {@inheritDoc}
*/
public boolean exists(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = rootNode.find(mountPoint, target);
if (zipNode == null) {
return false;
} else {
final File cachedFile = zipNode.cachedFile;
return cachedFile == null || cachedFile.exists();
}
}
/**
* {@inheritDoc}
*/
public boolean isFile(final VirtualFile mountPoint, final VirtualFile target) {
final ZipNode zipNode = rootNode.find(mountPoint, target);
return zipNode != null && zipNode.entry != null;
}
/**
* {@inheritDoc}
*/
public boolean isDirectory(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = rootNode.find(mountPoint, target);
return zipNode != null && zipNode.entry == null;
}
/**
* {@inheritDoc}
*/
public List getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = getZipNode(mountPoint, target);
if (zipNode == null) {
return Collections.emptyList();
}
final Map children = zipNode.children;
if (children == null) {
return Collections.emptyList();
}
final Collection values = children.values();
final List names = new ArrayList(values.size());
for (ZipNode node : values) {
names.add(node.name);
}
return names;
}
/**
* {@inheritDoc}
*/
public CodeSigner[] getCodeSigners(VirtualFile mountPoint, VirtualFile target) {
final ZipNode zipNode = getZipNode(mountPoint, target);
if (zipNode == null) {
return null;
}
JarEntry jarEntry = zipNode.entry;
return jarEntry.getCodeSigners();
}
private ZipNode getZipNode(VirtualFile mountPoint, VirtualFile target) {
return rootNode.find(mountPoint, target);
}
private ZipNode getExistingZipNode(VirtualFile mountPoint, VirtualFile target)
throws FileNotFoundException {
final ZipNode zipNode = rootNode.find(mountPoint, target);
if (zipNode == null) {
throw new FileNotFoundException(target.getPathName());
}
return zipNode;
}
/**
* {@inheritDoc}
*/
public boolean isReadOnly() {
return true;
}
/**
* {@inheritDoc}
*/
public File getMountSource() {
return archiveFile;
}
public URI getRootURI() throws URISyntaxException {
return new URI("jar", archiveFile.toURI().toString() + "!/", null);
}
/**
* {@inheritDoc}
*/
public void close() throws IOException {
VFSLogger.ROOT_LOGGER.tracef("Closing zip filesystem %s", this);
VFSUtils.safeClose(new Closeable() {
public void close() throws IOException {
zipFile.close();
}
});
tempDir.close();
}
private File buildFile(File contentsDir, String name) {
List tokens = PathTokenizer.getTokens(name);
File currentFile = contentsDir;
for (String token : tokens) {
currentFile = new File(currentFile, token);
}
currentFile.getParentFile().mkdirs();
return currentFile;
}
private static final class ZipNode {
// immutable child map
private final Map children;
private final String name;
private final JarEntry entry;
private volatile File cachedFile;
private ZipNode(Map children, String name, JarEntry entry) {
this.children = children;
this.name = name;
this.entry = entry;
}
private ZipNode find(VirtualFile mountPoint, VirtualFile target) {
if (mountPoint.equals(target)) {
return this;
} else {
final ZipNode parent = find(mountPoint, target.getParent());
if (parent == null) {
return null;
}
final Map children = parent.children;
if (children == null) {
return null;
}
return children.get(target.getName());
}
}
}
}