blob: d5954151de2366252db8b4353c93f6cd7f117061 [file] [log] [blame]
package org.eclipse.jdt.internal.core.builder;
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ProviderNotFoundException;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.function.Predicate;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IModule;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
public class ClasspathMultiReleaseJar extends ClasspathJar {
private java.nio.file.FileSystem fs = null;
Path releasePath = null;
ClasspathMultiReleaseJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
super(resource, accessRuleSet, externalAnnotationPath, isOnModulePath);
this.compliance = compliance;
initializeVersions();
}
ClasspathMultiReleaseJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
super(zipFilename, lastModified, accessRuleSet, externalAnnotationPath, isOnModulePath);
this.compliance = compliance;
initializeVersions();
}
public ClasspathMultiReleaseJar(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
this(zipFile.getName(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance);
this.zipFile = zipFile;
this.closeZipFileAtEnd = true;
}
public ClasspathMultiReleaseJar(String fileName, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
this(fileName, 0, accessRuleSet, externalAnnotationPath, isOnModulePath, compliance);
if (externalAnnotationPath != null)
this.externalAnnotationPath = externalAnnotationPath.toString();
}
private void initializeVersions() {
Path filePath = Paths.get(this.zipFilename);
if (Files.exists(filePath)) {
URI uri = URI.create("jar:" + filePath.toUri()); //$NON-NLS-1$
try {
this.fs = FileSystems.getFileSystem(uri);
if (this.fs == null) {
HashMap<String, ?> env = new HashMap<>();
this.fs = FileSystems.newFileSystem(uri, env);
}
} catch (FileSystemNotFoundException | ProviderNotFoundException e) {
// move on
} catch (IOException e) {
// move on
}
if (this.fs == null) {
this.releasePath = null;
} else {
this.releasePath = this.fs.getPath("/", "META-INF", "versions", this.compliance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (!Files.exists(this.releasePath)) {
this.releasePath = null;
try {
this.fs.close();
} catch (IOException e) {
// ignore
}
}
}
}
}
@Override
protected String readJarContent(final SimpleSet packageSet) {
String[] modInfo = new String[1];
modInfo[0] = super.readJarContent(packageSet);
try {
if (this.releasePath != null && Files.exists(this.releasePath)) {
// go through the packages
try (DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(this.releasePath)) {
for (final java.nio.file.Path subdir: stream) {
Files.walkFileTree(subdir, new FileVisitor<java.nio.file.Path>() {
@Override
public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs)
throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs)
throws IOException {
Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(file);
addToPackageSet(packageSet, p.toString(), false);
if (modInfo[0] == null) {
if (p.getFileName().toString().equalsIgnoreCase(IModule.MODULE_INFO_CLASS)) {
modInfo[0] = ClasspathMultiReleaseJar.this.releasePath.relativize(file).toString();
}
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(java.nio.file.Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc)
throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
}
}
} catch (Exception e) {
// move on;
}
return modInfo[0];
}
@Override
public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate<String> moduleNameFilter) {
if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case
if (this.releasePath != null) {
try {
Path path = this.releasePath.resolve(qualifiedPackageName).resolve(binaryFileName);
byte[] content = Files.readAllBytes(path);
IBinaryType reader = null;
if (content != null) {
reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray());
}
if (reader != null) {
char[] modName = this.module == null ? null : this.module.name();
if (reader instanceof ClassFileReader) {
ClassFileReader classReader = (ClassFileReader) reader;
if (classReader.moduleName == null)
classReader.moduleName = modName;
else
modName = classReader.moduleName;
}
String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
if (this.externalAnnotationPath != null) {
try {
if (this.annotationZipFile == null) {
this.annotationZipFile = ExternalAnnotationDecorator
.getAnnotationZipFile(this.externalAnnotationPath, null);
}
reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath,
fileNameWithoutExtension, this.annotationZipFile);
} catch (IOException e) {
// don't let error on annotations fail class reading
}
if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.NOT_EEA_CONFIGURED) {
// ensure a reader that answers NO_EEA_FILE
reader = new ExternalAnnotationDecorator(reader, null);
}
}
if (this.accessRuleSet == null)
return new NameEnvironmentAnswer(reader, null, modName);
return new NameEnvironmentAnswer(reader,
this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()),
modName);
}
} catch (IOException | ClassFormatException e) {
// treat as if class file is missing
}
}
return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly, moduleNameFilter);
}
}