📄 zipfileindex.java
字号:
package com.sun.tools.javac.zip;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.*;
/** This class implements building of index of a zip archive and access to it's context.
* It also uses prebuild index if available. It supports invocations where it will
* serialize an optimized zip index file to disk.
*
* In oreder to use secondary index file make sure the option "usezipindex" is in the Options object,
* when JavacFileManager is invoked. (You can pass "-XDusezipindex" on the command line.
*
* Location where to look for/generate optimized zip index files can be provided using
* "-XDcachezipindexdir=<directory>". If this flag is not provided, the dfault location is
* the value of the "java.io.tmpdir" system property.
*
* If key "-XDwritezipindexfiles" is specified, there will be new optimized index file
* created for each archive, used by the compiler for compilation, at location,
* specified by "cachezipindexdir" option.
*
* If nonBatchMode option is specified (-XDnonBatchMode) the compiler will use timestamp
* checking to reindex the zip files if it is needed. In batch mode the timestamps are not checked
* and the compiler uses the cached indexes.
*/
public class ZipFileIndex {
private static final String MIN_CHAR = String.valueOf(Character.MIN_VALUE);
private static final String MAX_CHAR = String.valueOf(Character.MAX_VALUE);
public final static long NOT_MODIFIED = Long.MIN_VALUE;
private final static com.sun.tools.javac.util.List EMPTY_LIST = com.sun.tools.javac.util.List.nil();
private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>();
private static ReentrantLock lock = new ReentrantLock();
private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
private Map<String, DirectoryEntry> directories = Collections.EMPTY_MAP;
private Set<String> allDirs = Collections.EMPTY_SET;
// ZipFileIndex data entries
private File zipFile;
private long zipFileLastModified = NOT_MODIFIED;
private RandomAccessFile zipRandomFile;
private ZipFileIndexEntry[] entries;
private boolean readFromIndex = false;
private File zipIndexFile = null;
private boolean triedToReadIndex = false;
private int symbolFilePrefixLength = 0;
private boolean hasPopulatedData = false;
private long lastReferenceTimeStamp = NOT_MODIFIED;
private boolean usePreindexedCache = false;
private String preindexedCacheLocation = null;
private boolean writeIndex = false;
/**
* Returns a list of all ZipFileIndex entries
*
* @return A list of ZipFileIndex entries, or an empty list
*/
public static List<ZipFileIndex> getZipFileIndexes() {
return getZipFileIndexes(false);
}
/**
* Returns a list of all ZipFileIndex entries
*
* @param openedOnly If true it returns a list of only opened ZipFileIndex entries, otherwise
* all ZipFileEntry(s) are included into the list.
* @return A list of ZipFileIndex entries, or an empty list
*/
public static List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) {
List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>();
lock.lock();
try {
zipFileIndexes.addAll(zipFileIndexCache.values());
if (openedOnly) {
for(ZipFileIndex elem : zipFileIndexes) {
if (!elem.isOpen()) {
zipFileIndexes.remove(elem);
}
}
}
}
finally {
lock.unlock();
}
return zipFileIndexes;
}
public boolean isOpen() {
lock.lock();
try {
return zipRandomFile != null;
}
finally {
lock.unlock();
}
}
public static ZipFileIndex getZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException {
ZipFileIndex zi = null;
lock.lock();
try {
zi = getExistingZipIndex(zipFile);
if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) {
zi = new ZipFileIndex(zipFile, symbolFilePrefixLen, writeIndex,
useCache, cacheLocation);
zipFileIndexCache.put(zipFile, zi);
}
}
finally {
lock.unlock();
}
return zi;
}
public static ZipFileIndex getExistingZipIndex(File zipFile) {
lock.lock();
try {
return zipFileIndexCache.get(zipFile);
}
finally {
lock.unlock();
}
}
public static void clearCache() {
lock.lock();
try {
zipFileIndexCache.clear();
}
finally {
lock.unlock();
}
}
public static void clearCache(long timeNotUsed) {
lock.lock();
try {
Iterator<File> cachedFileIterator = zipFileIndexCache.keySet().iterator();
while (cachedFileIterator.hasNext()) {
File cachedFile = cachedFileIterator.next();
ZipFileIndex cachedZipIndex = zipFileIndexCache.get(cachedFile);
if (cachedZipIndex != null) {
long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed;
if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow...
System.currentTimeMillis() > timeToTest) {
zipFileIndexCache.remove(cachedFile);
}
}
}
}
finally {
lock.unlock();
}
}
public static void removeFromCache(File file) {
lock.lock();
try {
zipFileIndexCache.remove(file);
}
finally {
lock.unlock();
}
}
/** Sets already opened list of ZipFileIndexes from an outside client
* of the compiler. This functionality should be used in a non-batch clients of the compiler.
*/
public static void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException {
lock.lock();
try {
if (zipFileIndexCache.isEmpty()) {
throw new IllegalStateException("Setting opened indexes should be called only when the ZipFileCache is empty. Call JavacFileManager.flush() before calling this method.");
}
for (ZipFileIndex zfi : indexes) {
zipFileIndexCache.put(zfi.zipFile, zfi);
}
}
finally {
lock.unlock();
}
}
private ZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean writeIndex,
boolean useCache, String cacheLocation) throws IOException {
this.zipFile = zipFile;
this.symbolFilePrefixLength = symbolFilePrefixLen;
this.writeIndex = writeIndex;
this.usePreindexedCache = useCache;
this.preindexedCacheLocation = cacheLocation;
if (zipFile != null) {
this.zipFileLastModified = zipFile.lastModified();
}
// Validate integrity of the zip file
checkIndex();
}
public String toString() {
return "ZipFileIndex of file:(" + zipFile + ")";
}
// Just in case...
protected void finalize() {
closeFile();
}
private boolean isUpToDate() {
if (zipFile != null &&
((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) &&
hasPopulatedData) {
return true;
}
return false;
}
/**
* Here we need to make sure that the ZipFileIndex is valid. Check the timestamp of the file and
* if its the same as the one at the time the index was build we don't need to reopen anything.
*/
private void checkIndex() throws IOException {
boolean isUpToDate = true;
if (!isUpToDate()) {
closeFile();
isUpToDate = false;
}
if (zipRandomFile != null || isUpToDate) {
lastReferenceTimeStamp = System.currentTimeMillis();
return;
}
hasPopulatedData = true;
if (readIndex()) {
lastReferenceTimeStamp = System.currentTimeMillis();
return;
}
directories = Collections.EMPTY_MAP;
allDirs = Collections.EMPTY_SET;
try {
openFile();
long totalLength = zipRandomFile.length();
ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this);
directory.buildIndex();
} finally {
if (zipRandomFile != null) {
closeFile();
}
}
lastReferenceTimeStamp = System.currentTimeMillis();
}
private void openFile() throws FileNotFoundException {
if (zipRandomFile == null && zipFile != null) {
zipRandomFile = new RandomAccessFile(zipFile, "r");
}
}
private void cleanupState() {
// Make sure there is a valid but empty index if the file doesn't exist
entries = ZipFileIndexEntry.EMPTY_ARRAY;
directories = Collections.EMPTY_MAP;
zipFileLastModified = NOT_MODIFIED;
allDirs = Collections.EMPTY_SET;
}
public void close() {
lock.lock();
try {
writeIndex();
closeFile();
}
finally {
lock.unlock();
}
}
private void closeFile() {
if (zipRandomFile != null) {
try {
zipRandomFile.close();
} catch (IOException ex) {
}
zipRandomFile = null;
}
}
/**
* Returns the ZipFileIndexEntry for an absolute path, if there is one.
*/
public ZipFileIndexEntry getZipIndexEntry(String path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock();
try {
checkIndex();
String lookFor = "";
int lastSepIndex = path.lastIndexOf(File.separatorChar);
boolean noSeparator = false;
if (lastSepIndex == -1) {
noSeparator = true;
}
DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
return de == null ? null : de.getEntry(lookFor);
}
catch (IOException e) {
return null;
}
finally {
lock.unlock();
}
}
/**
* Returns a javac List of filenames within an absolute path in the ZipFileIndex.
*/
public com.sun.tools.javac.util.List<String> getFiles(String path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock();
try {
checkIndex();
DirectoryEntry de = directories.get(path);
com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getFiles();
if (ret == null) {
return EMPTY_LIST;
}
return ret;
}
catch (IOException e) {
return EMPTY_LIST;
}
finally {
lock.unlock();
}
}
public List<String> getAllDirectories(String path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock();
try {
checkIndex();
path = path.intern();
DirectoryEntry de = directories.get(path);
com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
if (ret == null) {
return EMPTY_LIST;
}
return ret;
}
catch (IOException e) {
return EMPTY_LIST;
}
finally {
lock.unlock();
}
}
public Set<String> getAllDirectories() {
lock.lock();
try {
checkIndex();
if (allDirs == Collections.EMPTY_SET) {
Set<String> alldirs = new HashSet<String>();
Iterator<String> dirsIter = directories.keySet().iterator();
while (dirsIter.hasNext()) {
alldirs.add(new String(dirsIter.next()));
}
allDirs = alldirs;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -