< prev index next >

src/java.base/share/classes/jdk/internal/module/ModulePath.java

Print this page




 496 
 497         // map names of service configuration files to service names
 498         Set<String> serviceNames = configFiles.stream()
 499                 .map(this::toServiceName)
 500                 .flatMap(Optional::stream)
 501                 .collect(Collectors.toSet());
 502 
 503         // parse each service configuration file
 504         for (String sn : serviceNames) {
 505             JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
 506             List<String> providerClasses = new ArrayList<>();
 507             try (InputStream in = jf.getInputStream(entry)) {
 508                 BufferedReader reader
 509                     = new BufferedReader(new InputStreamReader(in, "UTF-8"));
 510                 String cn;
 511                 while ((cn = nextLine(reader)) != null) {
 512                     if (cn.length() > 0) {
 513                         String pn = packageName(cn);
 514                         if (!packages.contains(pn)) {
 515                             String msg = "Provider class " + cn + " not in module";
 516                             throw new IOException(msg);
 517                         }
 518                         providerClasses.add(cn);
 519                     }
 520                 }
 521             }
 522             if (!providerClasses.isEmpty())
 523                 builder.provides(sn, providerClasses);
 524         }
 525 
 526         // Main-Class attribute if it exists
 527         Manifest man = jf.getManifest();
 528         if (man != null) {
 529             Attributes attrs = man.getMainAttributes();
 530             String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
 531             if (mainClass != null) {
 532                 mainClass = mainClass.replace("/", ".");
 533                 String pn = packageName(mainClass);
 534                 if (!packages.contains(pn)) {
 535                     String msg = "Main-Class " + mainClass + " not in module";
 536                     throw new IOException(msg);
 537                 }
 538                 builder.mainClass(mainClass);
 539             }
 540         }
 541 
 542         return builder.build();
 543     }
 544 
 545     /**
 546      * Patterns used to derive the module name from a JAR file name.
 547      */
 548     private static class Patterns {
 549         static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
 550         static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
 551         static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
 552         static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
 553         static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
 554         static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
 555     }
 556 


 592      * Returns a {@code ModuleReference} to a module in modular JAR file on
 593      * the file system.
 594      *
 595      * @throws IOException
 596      * @throws FindException
 597      * @throws InvalidModuleDescriptorException
 598      */
 599     private ModuleReference readJar(Path file) throws IOException {
 600         try (JarFile jf = new JarFile(file.toFile(),
 601                                       true,               // verify
 602                                       ZipFile.OPEN_READ,
 603                                       releaseVersion))
 604         {
 605             ModuleInfo.Attributes attrs;
 606             JarEntry entry = jf.getJarEntry(MODULE_INFO);
 607             if (entry == null) {
 608 
 609                 // no module-info.class so treat it as automatic module
 610                 try {
 611                     ModuleDescriptor md = deriveModuleDescriptor(jf);
 612                     attrs = new ModuleInfo.Attributes(md, null, null);
 613                 } catch (IllegalArgumentException e) {
 614                     throw new FindException(
 615                         "Unable to derive module descriptor for: "
 616                         + jf.getName(), e);
 617                 }
 618 
 619             } else {
 620                 attrs = ModuleInfo.read(jf.getInputStream(entry),
 621                                         () -> jarPackages(jf));
 622             }
 623 
 624             return ModuleReferences.newJarModule(attrs, patcher, file);
 625         }
 626     }
 627 
 628 
 629     // -- exploded directories --
 630 
 631     private Set<String> explodedPackages(Path dir) {
 632         try {
 633             return Files.find(dir, Integer.MAX_VALUE,
 634                               ((path, attrs) -> attrs.isRegularFile()))
 635                     .map(path -> dir.relativize(path))


 655             attrs = ModuleInfo.read(new BufferedInputStream(in),
 656                                     () -> explodedPackages(dir));
 657         } catch (NoSuchFileException e) {
 658             // for now
 659             return null;
 660         }
 661         return ModuleReferences.newExplodedModule(attrs, patcher, dir);
 662     }
 663 
 664     /**
 665      * Maps a type name to its package name.
 666      */
 667     private static String packageName(String cn) {
 668         int index = cn.lastIndexOf('.');
 669         return (index == -1) ? "" : cn.substring(0, index);
 670     }
 671 
 672     /**
 673      * Maps the name of an entry in a JAR or ZIP file to a package name.
 674      *
 675      * @throws IllegalArgumentException if the name is a class file in
 676      *         the top-level directory of the JAR/ZIP file (and it's
 677      *         not module-info.class)
 678      */
 679     private Optional<String> toPackageName(String name) {
 680         assert !name.endsWith("/");
 681         int index = name.lastIndexOf("/");
 682         if (index == -1) {
 683             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
 684                 throw new IllegalArgumentException(name
 685                         + " found in top-level directory"
 686                         + " (unnamed package not allowed in module)");
 687             }
 688             return Optional.empty();
 689         }
 690 
 691         String pn = name.substring(0, index).replace('/', '.');
 692         if (Checks.isPackageName(pn)) {
 693             return Optional.of(pn);
 694         } else {
 695             // not a valid package name
 696             return Optional.empty();
 697         }
 698     }
 699 
 700     /**
 701      * Maps the relative path of an entry in an exploded module to a package
 702      * name.
 703      *
 704      * @throws IllegalArgumentException if the name is a class file in
 705      *          the top-level directory (and it's not module-info.class)
 706      */
 707     private Optional<String> toPackageName(Path file) {
 708         assert file.getRoot() == null;
 709 
 710         Path parent = file.getParent();
 711         if (parent == null) {
 712             String name = file.toString();
 713             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
 714                 throw new IllegalArgumentException(name
 715                         + " found in top-level directory"
 716                         + " (unnamed package not allowed in module)");
 717             }
 718             return Optional.empty();
 719         }
 720 
 721         String pn = parent.toString().replace(File.separatorChar, '.');
 722         if (Checks.isPackageName(pn)) {
 723             return Optional.of(pn);
 724         } else {
 725             // not a valid package name
 726             return Optional.empty();
 727         }
 728     }
 729 
 730     private static final PerfCounter scanTime
 731         = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
 732     private static final PerfCounter moduleCount
 733         = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
 734 }


 496 
 497         // map names of service configuration files to service names
 498         Set<String> serviceNames = configFiles.stream()
 499                 .map(this::toServiceName)
 500                 .flatMap(Optional::stream)
 501                 .collect(Collectors.toSet());
 502 
 503         // parse each service configuration file
 504         for (String sn : serviceNames) {
 505             JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
 506             List<String> providerClasses = new ArrayList<>();
 507             try (InputStream in = jf.getInputStream(entry)) {
 508                 BufferedReader reader
 509                     = new BufferedReader(new InputStreamReader(in, "UTF-8"));
 510                 String cn;
 511                 while ((cn = nextLine(reader)) != null) {
 512                     if (cn.length() > 0) {
 513                         String pn = packageName(cn);
 514                         if (!packages.contains(pn)) {
 515                             String msg = "Provider class " + cn + " not in module";
 516                             throw new InvalidModuleDescriptorException(msg);
 517                         }
 518                         providerClasses.add(cn);
 519                     }
 520                 }
 521             }
 522             if (!providerClasses.isEmpty())
 523                 builder.provides(sn, providerClasses);
 524         }
 525 
 526         // Main-Class attribute if it exists
 527         Manifest man = jf.getManifest();
 528         if (man != null) {
 529             Attributes attrs = man.getMainAttributes();
 530             String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
 531             if (mainClass != null) {
 532                 mainClass = mainClass.replace("/", ".");
 533                 String pn = packageName(mainClass);
 534                 if (!packages.contains(pn)) {
 535                     String msg = "Main-Class " + mainClass + " not in module";
 536                     throw new InvalidModuleDescriptorException(msg);
 537                 }
 538                 builder.mainClass(mainClass);
 539             }
 540         }
 541 
 542         return builder.build();
 543     }
 544 
 545     /**
 546      * Patterns used to derive the module name from a JAR file name.
 547      */
 548     private static class Patterns {
 549         static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
 550         static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
 551         static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
 552         static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
 553         static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
 554         static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
 555     }
 556 


 592      * Returns a {@code ModuleReference} to a module in modular JAR file on
 593      * the file system.
 594      *
 595      * @throws IOException
 596      * @throws FindException
 597      * @throws InvalidModuleDescriptorException
 598      */
 599     private ModuleReference readJar(Path file) throws IOException {
 600         try (JarFile jf = new JarFile(file.toFile(),
 601                                       true,               // verify
 602                                       ZipFile.OPEN_READ,
 603                                       releaseVersion))
 604         {
 605             ModuleInfo.Attributes attrs;
 606             JarEntry entry = jf.getJarEntry(MODULE_INFO);
 607             if (entry == null) {
 608 
 609                 // no module-info.class so treat it as automatic module
 610                 try {
 611                     ModuleDescriptor md = deriveModuleDescriptor(jf);
 612                     attrs = new ModuleInfo.Attributes(md, null, null, null);
 613                 } catch (RuntimeException e) {
 614                     throw new FindException("Unable to derive module descriptor for "

 615                                             + jf.getName(), e);
 616                 }
 617 
 618             } else {
 619                 attrs = ModuleInfo.read(jf.getInputStream(entry),
 620                                         () -> jarPackages(jf));
 621             }
 622 
 623             return ModuleReferences.newJarModule(attrs, patcher, file);
 624         }
 625     }
 626 
 627 
 628     // -- exploded directories --
 629 
 630     private Set<String> explodedPackages(Path dir) {
 631         try {
 632             return Files.find(dir, Integer.MAX_VALUE,
 633                               ((path, attrs) -> attrs.isRegularFile()))
 634                     .map(path -> dir.relativize(path))


 654             attrs = ModuleInfo.read(new BufferedInputStream(in),
 655                                     () -> explodedPackages(dir));
 656         } catch (NoSuchFileException e) {
 657             // for now
 658             return null;
 659         }
 660         return ModuleReferences.newExplodedModule(attrs, patcher, dir);
 661     }
 662 
 663     /**
 664      * Maps a type name to its package name.
 665      */
 666     private static String packageName(String cn) {
 667         int index = cn.lastIndexOf('.');
 668         return (index == -1) ? "" : cn.substring(0, index);
 669     }
 670 
 671     /**
 672      * Maps the name of an entry in a JAR or ZIP file to a package name.
 673      *
 674      * @throws InvalidModuleDescriptorException if the name is a class file in
 675      *         the top-level directory of the JAR/ZIP file (and it's not
 676      *         module-info.class)
 677      */
 678     private Optional<String> toPackageName(String name) {
 679         assert !name.endsWith("/");
 680         int index = name.lastIndexOf("/");
 681         if (index == -1) {
 682             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
 683                 String msg = name + " found in top-level directory"
 684                              + " (unnamed package not allowed in module)";
 685                 throw new InvalidModuleDescriptorException(msg);
 686             }
 687             return Optional.empty();
 688         }
 689 
 690         String pn = name.substring(0, index).replace('/', '.');
 691         if (Checks.isPackageName(pn)) {
 692             return Optional.of(pn);
 693         } else {
 694             // not a valid package name
 695             return Optional.empty();
 696         }
 697     }
 698 
 699     /**
 700      * Maps the relative path of an entry in an exploded module to a package
 701      * name.
 702      *
 703      * @throws InvalidModuleDescriptorException if the name is a class file in
 704      *         the top-level directory (and it's not module-info.class)
 705      */
 706     private Optional<String> toPackageName(Path file) {
 707         assert file.getRoot() == null;
 708 
 709         Path parent = file.getParent();
 710         if (parent == null) {
 711             String name = file.toString();
 712             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
 713                 String msg = name + " found in top-level directory"
 714                              + " (unnamed package not allowed in module)";
 715                 throw new InvalidModuleDescriptorException(msg);
 716             }
 717             return Optional.empty();
 718         }
 719 
 720         String pn = parent.toString().replace(File.separatorChar, '.');
 721         if (Checks.isPackageName(pn)) {
 722             return Optional.of(pn);
 723         } else {
 724             // not a valid package name
 725             return Optional.empty();
 726         }
 727     }
 728 
 729     private static final PerfCounter scanTime
 730         = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
 731     private static final PerfCounter moduleCount
 732         = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
 733 }
< prev index next >