extract core part of JarHandler

This commit is contained in:
Dmitry Jemerov
2011-10-14 15:33:13 +02:00
parent 81eb7079c9
commit e3d271da0e
2 changed files with 227 additions and 135 deletions
@@ -0,0 +1,221 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* 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 com.intellij.openapi.vfs.impl.jar;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.TimedReference;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public abstract class CoreJarHandler {
protected final TimedReference<ZipFile> myZipFile = new TimedReference<ZipFile>(null);
protected SoftReference<Map<String, EntryInfo>> myRelPathsToEntries = new SoftReference<Map<String, EntryInfo>>(null);
protected final Object lock = new Object();
protected final String myBasePath;
protected static class EntryInfo {
public EntryInfo(final String shortName, final EntryInfo parent, final boolean directory) {
this.shortName = new String(shortName);
this.parent = parent;
isDirectory = directory;
}
final boolean isDirectory;
protected final String shortName;
final EntryInfo parent;
}
public CoreJarHandler(String path) {
myBasePath = path;
}
@NotNull
protected Map<String, EntryInfo> initEntries() {
synchronized (lock) {
Map<String, EntryInfo> map = myRelPathsToEntries.get();
if (map == null) {
final ZipFile zip = getZip();
map = new THashMap<String, EntryInfo>();
if (zip != null) {
map.put("", new EntryInfo("", null, true));
final Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
final String name = entry.getName();
final boolean isDirectory = name.endsWith("/");
getOrCreate(isDirectory ? name.substring(0, name.length() - 1) : name, isDirectory, map);
}
myRelPathsToEntries = new SoftReference<Map<String, EntryInfo>>(map);
}
}
return map;
}
}
public File getMirrorFile(File originalFile) {
return originalFile;
}
@Nullable
public ZipFile getZip() {
ZipFile zip = myZipFile.get();
if (zip == null) {
try {
zip = new ZipFile(getMirrorFile(getOriginalFile()));
myZipFile.set(zip);
}
catch (IOException e) {
return null;
}
}
return zip;
}
protected File getOriginalFile() {
return new File(myBasePath);
}
private static EntryInfo getOrCreate(String entryName, boolean isDirectory, Map<String, EntryInfo> map) {
EntryInfo info = map.get(entryName);
if (info == null) {
int idx = entryName.lastIndexOf('/');
final String parentEntryName = idx > 0 ? entryName.substring(0, idx) : "";
String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName;
if (".".equals(shortName)) return getOrCreate(parentEntryName, true, map);
info = new EntryInfo(shortName, getOrCreate(parentEntryName, true, map), isDirectory);
map.put(entryName, info);
}
return info;
}
@NotNull
public String[] list(@NotNull final VirtualFile file) {
synchronized (lock) {
EntryInfo parentEntry = getEntryInfo(file);
Set<String> names = new HashSet<String>();
for (EntryInfo info : getEntriesMap().values()) {
if (info.parent == parentEntry) {
names.add(info.shortName);
}
}
return ArrayUtil.toStringArray(names);
}
}
protected EntryInfo getEntryInfo(final VirtualFile file) {
String parentPath = getRelativePath(file);
return getEntriesMap().get(parentPath);
}
protected Map<String, EntryInfo> getEntriesMap() {
return initEntries();
}
private String getRelativePath(final VirtualFile file) {
final String path = file.getPath().substring(myBasePath.length() + 1);
return path.startsWith("/") ? path.substring(1) : path;
}
@Nullable
private ZipEntry convertToEntry(VirtualFile file) {
String path = getRelativePath(file);
final ZipFile zip = getZip();
return zip != null ? zip.getEntry(path) : null;
}
public long getLength(@NotNull final VirtualFile file) {
synchronized (lock) {
final ZipEntry entry = convertToEntry(file);
return entry != null ? entry.getSize() : 0;
}
}
@NotNull
public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException {
return new ByteArrayInputStream(contentsToByteArray(file));
}
@NotNull
public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException {
synchronized (lock) {
final ZipEntry entry = convertToEntry(file);
if (entry == null) {
return new byte[0];
}
final ZipFile zip = getZip();
assert zip != null : file;
final InputStream stream = zip.getInputStream(entry);
assert stream != null : file;
try {
return FileUtil.loadBytes(stream, (int)entry.getSize());
}
finally {
stream.close();
}
}
}
public long getTimeStamp(@NotNull final VirtualFile file) {
if (file.getParent() == null) return -1L; // Optimization
synchronized (lock) {
final ZipEntry entry = convertToEntry(file);
return entry != null ? entry.getTime() : -1L;
}
}
public boolean isDirectory(@NotNull final VirtualFile file) {
if (file.getParent() == null) return true; // Optimization
synchronized (lock) {
final String path = getRelativePath(file);
final EntryInfo info = getEntriesMap().get(path);
return info == null || info.isDirectory;
}
}
public boolean exists(@NotNull final VirtualFile fileOrDirectory) {
if (fileOrDirectory.getParent() == null) {
// Optimization. Do not build entries if asked for jar root existence.
return myZipFile.get() != null || getOriginalFile().exists();
}
return getEntryInfo(fileOrDirectory) != null;
}
}
@@ -30,46 +30,22 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.newvfs.FileSystemInterface;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.TimedReference;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.lang.ref.SoftReference;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
public class JarHandler implements FileSystemInterface {
public class JarHandler extends CoreJarHandler implements FileSystemInterface {
@NonNls private static final String JARS_FOLDER = "jars";
private final Object lock = new Object();
private final TimedReference<ZipFile> myZipFile = new TimedReference<ZipFile>(null);
private final JarFileSystemImpl myFileSystem;
private final String myBasePath;
private SoftReference<Map<String, EntryInfo>> myRelPathsToEntries = new SoftReference<Map<String, EntryInfo>>(null);
private static class EntryInfo {
public EntryInfo(final String shortName, final EntryInfo parent, final boolean directory) {
this.shortName = new String(shortName);
this.parent = parent;
isDirectory = directory;
}
final boolean isDirectory;
private final String shortName;
final EntryInfo parent;
}
public JarHandler(final JarFileSystemImpl fileSystem, String path) {
super(path);
myFileSystem = fileSystem;
myBasePath = path;
}
public void refreshLocalFileForJar() {
@@ -98,75 +74,7 @@ public class JarHandler implements FileSystemInterface {
}
}
@NotNull
private Map<String, EntryInfo> initEntries() {
synchronized (lock) {
Map<String, EntryInfo> map = myRelPathsToEntries.get();
if (map == null) {
final ZipFile zip = getZip();
map = new THashMap<String, EntryInfo>();
if (zip != null) {
map.put("", new EntryInfo("", null, true));
final Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
final String name = entry.getName();
final boolean isDirectory = name.endsWith("/");
getOrCreate(isDirectory ? name.substring(0, name.length() - 1) : name, isDirectory, map);
}
myRelPathsToEntries = new SoftReference<Map<String, EntryInfo>>(map);
}
}
return map;
}
}
private static EntryInfo getOrCreate(String entryName, boolean isDirectory, Map<String, EntryInfo> map) {
EntryInfo info = map.get(entryName);
if (info == null) {
int idx = entryName.lastIndexOf('/');
final String parentEntryName = idx > 0 ? entryName.substring(0, idx) : "";
String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName;
if (".".equals(shortName)) return getOrCreate(parentEntryName, true, map);
info = new EntryInfo(shortName, getOrCreate(parentEntryName, true, map), isDirectory);
map.put(entryName, info);
}
return info;
}
@Override
@NotNull
public String[] list(@NotNull final VirtualFile file) {
synchronized (lock) {
EntryInfo parentEntry = getEntryInfo(file);
Set<String> names = new HashSet<String>();
for (EntryInfo info : getEntriesMap().values()) {
if (info.parent == parentEntry) {
names.add(info.shortName);
}
}
return ArrayUtil.toStringArray(names);
}
}
private EntryInfo getEntryInfo(final VirtualFile file) {
synchronized (lock) {
String parentPath = getRelativePath(file);
return getEntriesMap().get(parentPath);
}
}
private String getRelativePath(final VirtualFile file) {
final String path = file.getPath().substring(myBasePath.length() + 1);
return path.startsWith("/") ? path.substring(1) : path;
}
public File getMirrorFile(File originalFile) {
if (!myFileSystem.isMakeCopyOfJar(originalFile) || !originalFile.exists()) return originalFile;
@@ -225,33 +133,6 @@ public class JarHandler implements FileSystemInterface {
return mirror;
}
@Nullable
public ZipFile getZip() {
ZipFile zip = myZipFile.get();
if (zip == null) {
try {
zip = new ZipFile(getMirrorFile(getOriginalFile()));
myZipFile.set(zip);
}
catch (IOException e) {
return null;
}
}
return zip;
}
private File getOriginalFile() {
return new File(myBasePath);
}
@Nullable
private ZipEntry convertToEntry(VirtualFile file) {
String path = getRelativePath(file);
final ZipFile zip = getZip();
return zip != null ? zip.getEntry(path) : null;
}
@Override
public long getLength(@NotNull final VirtualFile file) {
synchronized (lock) {
@@ -263,7 +144,7 @@ public class JarHandler implements FileSystemInterface {
@Override
@NotNull
public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException {
return new BufferExposingByteArrayInputStream(contentsToByteArray(file));
return new ByteArrayInputStream(contentsToByteArray(file));
}
@Override
@@ -318,16 +199,6 @@ public class JarHandler implements FileSystemInterface {
return false;
}
@Override
public boolean exists(@NotNull final VirtualFile fileOrDirectory) {
if (fileOrDirectory.getParent() == null) {
// Optimization. Do not build entries if asked for jar root existence.
return myZipFile.get() != null || getOriginalFile().exists();
}
return getEntryInfo(fileOrDirectory) != null;
}
private static void throwReadOnly() throws IOException {
throw new IOException("Jar file system is read-only");
}