| package org.eclipse.jdt.internal.compiler.batch; |
| |
| import java.io.File; |
| 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.attribute.BasicFileAttributes; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.zip.ZipEntry; |
| |
| 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.NameEnvironmentAnswer; |
| import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; |
| import org.eclipse.jdt.internal.compiler.util.SuffixConstants; |
| import org.eclipse.jdt.internal.compiler.util.Util; |
| |
| public class ClasspathMultiReleaseJar extends ClasspathJar { |
| private java.nio.file.FileSystem fs = null; |
| Path releasePath = null; |
| String compliance = null; |
| |
| public ClasspathMultiReleaseJar(File file, boolean closeZipFileAtEnd, |
| AccessRuleSet accessRuleSet, String destinationPath, String compliance) { |
| super(file, closeZipFileAtEnd, accessRuleSet, destinationPath); |
| this.compliance = compliance; |
| } |
| @Override |
| public void initialize() throws IOException { |
| super.initialize(); |
| URI t = this.file.toURI(); |
| if (this.file.exists()) { |
| URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ |
| try { |
| this.fs = FileSystems.getFileSystem(uri); |
| } catch(FileSystemNotFoundException fne) { |
| // Ignore and move on |
| } |
| if (this.fs == null) { |
| HashMap<String, ?> env = new HashMap<>(); |
| try { |
| this.fs = FileSystems.newFileSystem(uri, env); |
| } catch (IOException e) { |
| // return |
| } |
| } |
| 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; |
| } |
| } |
| } |
| @SuppressWarnings("rawtypes") |
| @Override |
| public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { |
| if (this.releasePath == null) { |
| return super.getModulesDeclaringPackage(qualifiedPackageName, moduleName); |
| } |
| if (this.packageCache != null) |
| return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); |
| |
| this.packageCache = new HashSet<>(41); |
| this.packageCache.add(Util.EMPTY_STRING); |
| |
| for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { |
| String fileName = ((ZipEntry) e.nextElement()).getName(); |
| addToPackageCache(fileName, false); |
| } |
| 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 f, BasicFileAttributes attrs) |
| throws IOException { |
| Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(f); |
| addToPackageCache(p.toString(), false); |
| return FileVisitResult.CONTINUE; |
| } |
| |
| @Override |
| public FileVisitResult visitFileFailed(java.nio.file.Path f, 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) { |
| e.printStackTrace(); |
| // move on; |
| } |
| return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); |
| } |
| @Override |
| public NameEnvironmentAnswer findClass(char[] binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { |
| if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case |
| if (this.releasePath != null) { |
| try { |
| Path p = this.releasePath.resolve(qualifiedBinaryFileName); |
| byte[] content = Files.readAllBytes(p); |
| 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); |
| searchPaths: |
| if (this.annotationPaths != null) { |
| String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1); |
| for (String annotationPath : this.annotationPaths) { |
| try { |
| if (this.annotationZipFile == null) { |
| this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); |
| } |
| reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); |
| |
| if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { |
| break searchPaths; |
| } |
| } catch (IOException e) { |
| // don't let error on annotations fail class reading |
| } |
| } |
| // location is configured for external annotations, but no .eea found, decorate in order to answer 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); |
| } |
| } |