< 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

 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();

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

 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     // true if the found modules should return preview versions of resources
 89     // (this must only be set for system modules).
 90     private final boolean previewMode;
 91 
 92     // for patching modules, can be null
 93     private final ModulePatcher patcher;
 94 
 95     // the entries on this module path
 96     private final Path[] entries;
 97     private int next;
 98 
 99     // map of module name to module reference map for modules already located
100     private final Map<String, ModuleReference> cachedModules = new HashMap<>();
101 
102 
103     private ModulePath(Runtime.Version version,
104                        boolean isLinkPhase,
105                        boolean previewMode,
106                        ModulePatcher patcher,
107                        Path... entries) {
108         this.releaseVersion = version;
109         this.isLinkPhase = isLinkPhase;
110         this.previewMode = previewMode;
111         this.patcher = patcher;
112         this.entries = entries.clone();
113         for (Path entry : this.entries) {
114             Objects.requireNonNull(entry);
115         }
116     }
117 
118     /**
119      * Returns a ModuleFinder for an exploded JDK build where {@code moduleDir}
120      * is the $JAVA_HOME/modules directory. The modules may be patched by the
121      * given ModulePatcher.
122      *
123      * <p>Preview mode is only permitted for system modules, and this method
124      * should only be called from {@link SystemModuleFinders#ofSystem()}.
125      */
126     public static ModuleFinder of(ModulePatcher patcher, boolean previewMode, Path moduleDir) {
127         return new ModulePath(JarFile.runtimeVersion(), false, previewMode, patcher, moduleDir);
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. The modules
133      * may be patched by the given ModulePatcher.
134      */
135     public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
136         return new ModulePath(JarFile.runtimeVersion(), false, false, patcher, entries);
137     }
138 
139     /**
140      * Returns a ModuleFinder that locates modules on the file system by
141      * searching a sequence of directories and/or packaged modules.
142      */
143     public static ModuleFinder of(Path... entries) {
144         return of((ModulePatcher)null, entries);
145     }
146 
147     /**
148      * Returns a ModuleFinder that locates modules on the file system by
149      * searching a sequence of directories and/or packaged modules.
150      *
151      * @param version The release version to use for multi-release JAR files
152      * @param isLinkPhase {@code true} if the link phase to locate JMOD files
153      */
154     public static ModuleFinder of(Runtime.Version version,
155                                   boolean isLinkPhase,
156                                   Path... entries) {
157         return new ModulePath(version, isLinkPhase, false, null, entries);
158     }
159 
160 
161     @Override
162     public Optional<ModuleReference> find(String name) {
163         Objects.requireNonNull(name);
164 
165         // try cached modules
166         ModuleReference m = cachedModules.get(name);
167         if (m != null)
168             return Optional.of(m);
169 
170         // the module may not have been encountered yet
171         while (hasNextEntry()) {
172             scanNextEntry();
173             m = cachedModules.get(name);
174             if (m != null)
175                 return Optional.of(m);
176         }
177         return Optional.empty();

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