< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any

 53 import java.util.Set;
 54 import java.util.jar.Attributes;
 55 import java.util.jar.JarEntry;
 56 import java.util.jar.JarFile;
 57 import java.util.jar.Manifest;
 58 import java.util.regex.Matcher;
 59 import java.util.regex.Pattern;
 60 import java.util.stream.Collectors;
 61 import java.util.stream.Stream;
 62 import java.util.zip.ZipException;
 63 import java.util.zip.ZipFile;
 64 
 65 import sun.nio.cs.UTF_8;
 66 
 67 import jdk.internal.jmod.JmodFile;
 68 import jdk.internal.jmod.JmodFile.Section;
 69 import jdk.internal.perf.PerfCounter;
 70 
 71 /**
 72  * A {@code ModuleFinder} that locates modules on the file system by searching
 73  * a sequence of directories or packaged modules. The ModuleFinder can be
 74  * created to work in either the run-time or link-time phases. In both cases it
 75  * locates modular JAR and exploded modules. When created for link-time then it
 76  * additionally locates modules in JMOD files. The ModuleFinder can also
 77  * optionally patch any modules that it locates with a ModulePatcher.





 78  */
 79 
 80 public class ModulePath implements ModuleFinder {
 81     private static final String MODULE_INFO = "module-info.class";
 82 
 83     // the version to use for multi-release modular JARs
 84     private final Runtime.Version releaseVersion;
 85 
 86     // true for the link phase (supports modules packaged in JMOD format)
 87     private final boolean isLinkPhase;
 88 
 89     // for patching modules, can be null
 90     private final ModulePatcher patcher;
 91 



 92     // the entries on this module path
 93     private final Path[] entries;
 94     private int next;
 95 
 96     // map of module name to module reference map for modules already located
 97     private final Map<String, ModuleReference> cachedModules = new HashMap<>();
 98 
 99 
100     private ModulePath(Runtime.Version version,
101                        boolean isLinkPhase,
102                        ModulePatcher patcher,

103                        Path... entries) {
104         this.releaseVersion = version;
105         this.isLinkPhase = isLinkPhase;
106         this.patcher = patcher;

107         this.entries = entries.clone();
108         for (Path entry : this.entries) {
109             Objects.requireNonNull(entry);
110         }
111     }
112 
113     /**
114      * Returns a ModuleFinder that locates modules on the file system by
115      * searching a sequence of directories and/or packaged modules. The modules
116      * may be patched by the given ModulePatcher.
117      */
118     public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
119         return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries);
120     }
121 
122     /**
123      * Returns a ModuleFinder that locates modules on the file system by
124      * searching a sequence of directories and/or packaged modules.
125      */
126     public static ModuleFinder of(Path... entries) {
127         return of((ModulePatcher)null, entries);
128     }
129 
130     /**
131      * Returns a ModuleFinder that locates modules on the file system by
132      * searching a sequence of directories and/or packaged modules.
133      *
134      * @param version The release version to use for multi-release JAR files
135      * @param isLinkPhase {@code true} if the link phase to locate JMOD files
136      */
137     public static ModuleFinder of(Runtime.Version version,
138                                   boolean isLinkPhase,
139                                   Path... entries) {
140         return new ModulePath(version, isLinkPhase, null, entries);
141     }
142 















143 
144     @Override
145     public Optional<ModuleReference> find(String name) {
146         Objects.requireNonNull(name);
147 
148         // try cached modules
149         ModuleReference m = cachedModules.get(name);
150         if (m != null)
151             return Optional.of(m);
152 
153         // the module may not have been encountered yet
154         while (hasNextEntry()) {
155             scanNextEntry();
156             m = cachedModules.get(name);
157             if (m != null)
158                 return Optional.of(m);
159         }
160         return Optional.empty();
161     }
162 

675         }
676     }
677 
678     /**
679      * Returns a {@code ModuleReference} to an exploded module on the file
680      * system or {@code null} if {@code module-info.class} not found.
681      *
682      * @throws IOException
683      * @throws InvalidModuleDescriptorException
684      */
685     private ModuleReference readExplodedModule(Path dir) throws IOException {
686         Path mi = dir.resolve(MODULE_INFO);
687         ModuleInfo.Attributes attrs;
688         try (InputStream in = Files.newInputStream(mi)) {
689             attrs = ModuleInfo.read(new BufferedInputStream(in),
690                                     () -> explodedPackages(dir));
691         } catch (NoSuchFileException e) {
692             // for now
693             return null;
694         }
695         return ModuleReferences.newExplodedModule(attrs, patcher, dir);
696     }
697 
698     /**
699      * Maps a type name to its package name.
700      */
701     private static String packageName(String cn) {
702         int index = cn.lastIndexOf('.');
703         return (index == -1) ? "" : cn.substring(0, index);
704     }
705 
706     /**
707      * Maps the name of an entry in a JAR or ZIP file to a package name.
708      *
709      * @throws InvalidModuleDescriptorException if the name is a class file in
710      *         the top-level directory of the JAR/ZIP file (and it's not
711      *         module-info.class)
712      */
713     private Optional<String> toPackageName(String name) {
714         assert !name.endsWith("/");
715         int index = name.lastIndexOf("/");

  1 /*
  2  * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any

 53 import java.util.Set;
 54 import java.util.jar.Attributes;
 55 import java.util.jar.JarEntry;
 56 import java.util.jar.JarFile;
 57 import java.util.jar.Manifest;
 58 import java.util.regex.Matcher;
 59 import java.util.regex.Pattern;
 60 import java.util.stream.Collectors;
 61 import java.util.stream.Stream;
 62 import java.util.zip.ZipException;
 63 import java.util.zip.ZipFile;
 64 
 65 import sun.nio.cs.UTF_8;
 66 
 67 import jdk.internal.jmod.JmodFile;
 68 import jdk.internal.jmod.JmodFile.Section;
 69 import jdk.internal.perf.PerfCounter;
 70 
 71 /**
 72  * A {@code ModuleFinder} that locates modules on the file system by searching
 73  * a sequence of directories or packaged modules.
 74  *
 75  * <p> A ModulePath can be created to locate modules on a module path at run-time or
 76  * link-time. In both cases it supports modular JARs and exploded modules. At link-time
 77  * it additionally locates modules in JMOD files. The ModuleFinder can also optionally
 78  * patch the modules that it locates with a ModulePatcher.
 79  *
 80  * <p> A ModulePath can also be created to locate modules in a JDK exploded image. It
 81  * can optionally patch any modules that it locates with a ModulePatcher, and it can
 82  * support preview classes in META-INF/preview when running with preview features enabled.
 83  */
 84 
 85 public class ModulePath implements ModuleFinder {
 86     private static final String MODULE_INFO = "module-info.class";
 87 
 88     // the version to use for multi-release modular JARs
 89     private final Runtime.Version releaseVersion;
 90 
 91     // true for the link phase (supports modules packaged in JMOD format)
 92     private final boolean isLinkPhase;
 93 
 94     // for patching modules, can be null
 95     private final ModulePatcher patcher;
 96 
 97     // true for a module path to a JDK exploded image and preview features are enabled
 98     private final boolean previewMode;
 99 
100     // the entries on this module path
101     private final Path[] entries;
102     private int next;
103 
104     // map of module name to module reference for modules already located
105     private final Map<String, ModuleReference> cachedModules = new HashMap<>();
106 
107 
108     private ModulePath(Runtime.Version version,
109                        boolean isLinkPhase,
110                        ModulePatcher patcher,
111                        boolean previewMode,
112                        Path... entries) {
113         this.releaseVersion = version;
114         this.isLinkPhase = isLinkPhase;
115         this.patcher = patcher;
116         this.previewMode = previewMode;
117         this.entries = entries.clone();
118         for (Path entry : this.entries) {
119             Objects.requireNonNull(entry);
120         }
121     }
122 
123     /**
124      * Returns a ModuleFinder that locates modules on the file system by
125      * searching a sequence of directories and/or packaged modules. The modules
126      * may be patched by the given ModulePatcher.
127      */
128     public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
129         return new ModulePath(JarFile.runtimeVersion(), false, patcher, false, entries);
130     }
131 
132     /**
133      * Returns a ModuleFinder that locates modules on the file system by
134      * searching a sequence of directories and/or packaged modules.
135      */
136     public static ModuleFinder of(Path... entries) {
137         return of(null, entries);
138     }
139 
140     /**
141      * Returns a ModuleFinder that locates modules on the file system by
142      * searching a sequence of directories and/or packaged modules.
143      *
144      * @param version The release version to use for multi-release JAR files
145      * @param isLinkPhase {@code true} if the link phase to locate JMOD files
146      */
147     public static ModuleFinder of(Runtime.Version version,
148                                   boolean isLinkPhase,
149                                   Path... entries) {
150         return new ModulePath(version, isLinkPhase, null, false, entries);
151     }
152 
153     /**
154      * Returns a ModuleFinder that locates modules in a JDK exploded image.
155      * @param modulesDir the modules directory ($JAVA_HOME/modules)
156      * @param patcher the ModulePatcher or null
157      * @param previewMode true if preview features are enabled
158      */
159     public static ModuleFinder ofExplodedImage(Path modulesDir,
160                                                ModulePatcher patcher,
161                                                boolean previewMode) {
162         return new ModulePath(JarFile.runtimeVersion(), // not used for exploded image
163                               false,
164                               patcher,
165                               previewMode,
166                               modulesDir);
167     }
168 
169     @Override
170     public Optional<ModuleReference> find(String name) {
171         Objects.requireNonNull(name);
172 
173         // try cached modules
174         ModuleReference m = cachedModules.get(name);
175         if (m != null)
176             return Optional.of(m);
177 
178         // the module may not have been encountered yet
179         while (hasNextEntry()) {
180             scanNextEntry();
181             m = cachedModules.get(name);
182             if (m != null)
183                 return Optional.of(m);
184         }
185         return Optional.empty();
186     }
187 

700         }
701     }
702 
703     /**
704      * Returns a {@code ModuleReference} to an exploded module on the file
705      * system or {@code null} if {@code module-info.class} not found.
706      *
707      * @throws IOException
708      * @throws InvalidModuleDescriptorException
709      */
710     private ModuleReference readExplodedModule(Path dir) throws IOException {
711         Path mi = dir.resolve(MODULE_INFO);
712         ModuleInfo.Attributes attrs;
713         try (InputStream in = Files.newInputStream(mi)) {
714             attrs = ModuleInfo.read(new BufferedInputStream(in),
715                                     () -> explodedPackages(dir));
716         } catch (NoSuchFileException e) {
717             // for now
718             return null;
719         }
720         return ModuleReferences.newExplodedModule(attrs, patcher, previewMode, dir);
721     }
722 
723     /**
724      * Maps a type name to its package name.
725      */
726     private static String packageName(String cn) {
727         int index = cn.lastIndexOf('.');
728         return (index == -1) ? "" : cn.substring(0, index);
729     }
730 
731     /**
732      * Maps the name of an entry in a JAR or ZIP file to a package name.
733      *
734      * @throws InvalidModuleDescriptorException if the name is a class file in
735      *         the top-level directory of the JAR/ZIP file (and it's not
736      *         module-info.class)
737      */
738     private Optional<String> toPackageName(String name) {
739         assert !name.endsWith("/");
740         int index = name.lastIndexOf("/");
< prev index next >