39 import java.nio.file.Path; 40 import java.nio.file.attribute.BasicFileAttributes; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.LinkedHashSet; 44 import java.util.Map; 45 import java.util.Objects; 46 import java.util.Optional; 47 import java.util.Set; 48 import java.util.jar.Attributes; 49 import java.util.jar.JarEntry; 50 import java.util.jar.JarFile; 51 import java.util.jar.Manifest; 52 import java.util.regex.Matcher; 53 import java.util.regex.Pattern; 54 import java.util.stream.Collectors; 55 import java.util.stream.Stream; 56 import java.util.zip.ZipEntry; 57 import java.util.zip.ZipFile; 58 59 import jdk.internal.module.ConfigurableModuleFinder; 60 import jdk.internal.perf.PerfCounter; 61 62 63 /** 64 * A {@code ModuleFinder} that locates modules on the file system by searching 65 * a sequence of directories or packaged modules. 66 * 67 * The {@code ModuleFinder} can be configured to work in either the run-time 68 * or link-time phases. In both cases it locates modular JAR and exploded 69 * modules. When configured for link-time then it additionally locates 70 * modules in JMOD files. 71 */ 72 73 class ModulePath implements ConfigurableModuleFinder { 74 private static final String MODULE_INFO = "module-info.class"; 75 76 // the entries on this module path 77 private final Path[] entries; 78 private int next; 277 return readJMod(entry); 278 throw new FindException("JMOD files not supported: " + entry); 279 } 280 } 281 282 // skip hidden files 283 if (fn.startsWith(".") || Files.isHidden(entry)) { 284 return null; 285 } else { 286 throw new FindException("Unrecognized module: " + entry); 287 } 288 289 } catch (InvalidModuleDescriptorException e) { 290 throw new FindException("Error reading module: " + entry, e); 291 } 292 } 293 294 295 // -- jmod files -- 296 297 private Set<String> jmodPackages(ZipFile zf) { 298 return zf.stream() 299 .filter(e -> e.getName().startsWith("classes/") && 300 e.getName().endsWith(".class")) 301 .map(e -> toPackageName(e.getName().substring(8))) 302 .filter(pkg -> pkg.length() > 0) // module-info 303 .collect(Collectors.toSet()); 304 } 305 306 /** 307 * Returns a {@code ModuleReference} to a module in jmod file on the 308 * file system. 309 * 310 * @throws IOException 311 * @throws InvalidModuleDescriptorException 312 */ 313 private ModuleReference readJMod(Path file) throws IOException { 314 try (ZipFile zf = new ZipFile(file.toString())) { 315 ZipEntry ze = zf.getEntry("classes/" + MODULE_INFO); 316 if (ze == null) { 317 throw new IOException(MODULE_INFO + " is missing: " + file); 318 } 319 ModuleDescriptor md; 320 try (InputStream in = zf.getInputStream(ze)) { 321 md = ModuleDescriptor.read(in, () -> jmodPackages(zf)); 322 } 323 return ModuleReferences.newJModModule(md, file); 324 } 325 } 326 327 328 // -- JAR files -- 329 330 private static final String SERVICES_PREFIX = "META-INF/services/"; 331 332 /** 333 * Returns a container with the service type corresponding to the name of 334 * a services configuration file. 335 * 336 * For example, if called with "META-INF/services/p.S" then this method 337 * returns a container with the value "p.S". 338 */ 339 private Optional<String> toServiceName(String cf) { 340 assert cf.startsWith(SERVICES_PREFIX); 341 int index = cf.lastIndexOf("/") + 1; | 39 import java.nio.file.Path; 40 import java.nio.file.attribute.BasicFileAttributes; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.LinkedHashSet; 44 import java.util.Map; 45 import java.util.Objects; 46 import java.util.Optional; 47 import java.util.Set; 48 import java.util.jar.Attributes; 49 import java.util.jar.JarEntry; 50 import java.util.jar.JarFile; 51 import java.util.jar.Manifest; 52 import java.util.regex.Matcher; 53 import java.util.regex.Pattern; 54 import java.util.stream.Collectors; 55 import java.util.stream.Stream; 56 import java.util.zip.ZipEntry; 57 import java.util.zip.ZipFile; 58 59 import jdk.internal.jmod.JmodFile; 60 import jdk.internal.jmod.JmodFile.Section; 61 import jdk.internal.module.ConfigurableModuleFinder; 62 import jdk.internal.perf.PerfCounter; 63 64 65 /** 66 * A {@code ModuleFinder} that locates modules on the file system by searching 67 * a sequence of directories or packaged modules. 68 * 69 * The {@code ModuleFinder} can be configured to work in either the run-time 70 * or link-time phases. In both cases it locates modular JAR and exploded 71 * modules. When configured for link-time then it additionally locates 72 * modules in JMOD files. 73 */ 74 75 class ModulePath implements ConfigurableModuleFinder { 76 private static final String MODULE_INFO = "module-info.class"; 77 78 // the entries on this module path 79 private final Path[] entries; 80 private int next; 279 return readJMod(entry); 280 throw new FindException("JMOD files not supported: " + entry); 281 } 282 } 283 284 // skip hidden files 285 if (fn.startsWith(".") || Files.isHidden(entry)) { 286 return null; 287 } else { 288 throw new FindException("Unrecognized module: " + entry); 289 } 290 291 } catch (InvalidModuleDescriptorException e) { 292 throw new FindException("Error reading module: " + entry, e); 293 } 294 } 295 296 297 // -- jmod files -- 298 299 private Set<String> jmodPackages(JmodFile jf) { 300 return jf.stream() 301 .filter(e -> e.section() == Section.CLASSES) 302 .map(JmodFile.Entry::name) 303 .map(this::toPackageName) 304 .filter(pkg -> pkg.length() > 0) // module-info 305 .collect(Collectors.toSet()); 306 } 307 308 /** 309 * Returns a {@code ModuleReference} to a module in jmod file on the 310 * file system. 311 * 312 * @throws IOException 313 * @throws InvalidModuleDescriptorException 314 */ 315 private ModuleReference readJMod(Path file) throws IOException { 316 try (JmodFile jf = new JmodFile(file)) { 317 ModuleDescriptor md; 318 try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) { 319 md = ModuleDescriptor.read(in, () -> jmodPackages(jf)); 320 } 321 return ModuleReferences.newJModModule(md, file); 322 } 323 } 324 325 326 // -- JAR files -- 327 328 private static final String SERVICES_PREFIX = "META-INF/services/"; 329 330 /** 331 * Returns a container with the service type corresponding to the name of 332 * a services configuration file. 333 * 334 * For example, if called with "META-INF/services/p.S" then this method 335 * returns a container with the value "p.S". 336 */ 337 private Optional<String> toServiceName(String cf) { 338 assert cf.startsWith(SERVICES_PREFIX); 339 int index = cf.lastIndexOf("/") + 1; |