63 /**
64 * A {@code ModuleFinder} that finds modules that are linked into the
65 * run-time image.
66 *
67 * The modules linked into the run-time image are assumed to have the
68 * Packages attribute.
69 */
70
71 public class SystemModuleFinder implements ModuleFinder {
72
73 private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
74
75 private static final PerfCounter initTime
76 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
77 private static final PerfCounter moduleCount
78 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
79 private static final PerfCounter packageCount
80 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
81 private static final PerfCounter exportsCount
82 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
83 // ImageReader used to access all modules in the image
84 private static final ImageReader imageReader;
85
86 // singleton finder to find modules in the run-time images
87 private static final SystemModuleFinder INSTANCE;
88
89 public static SystemModuleFinder getInstance() {
90 return INSTANCE;
91 }
92
93 /**
94 * For now, the module references are created eagerly on the assumption
95 * that service binding will require all modules to be located.
96 */
97 static {
98 long t0 = System.nanoTime();
99 imageReader = ImageReaderFactory.getImageReader();
100
101 INSTANCE = new SystemModuleFinder();
102
103 initTime.addElapsedTimeFrom(t0);
104 }
105
106 private static boolean isFastPathSupported() {
107 return SystemModules.MODULE_NAMES.length > 0;
108 }
109
110 private static String[] moduleNames() {
111 if (isFastPathSupported())
112 // module names recorded at link time
113 return SystemModules.MODULE_NAMES;
114
115 // this happens when java.base is patched with java.base
116 // from an exploded image
117 return imageReader.getModuleNames();
118 }
119
120 // the set of modules in the run-time image
121 private final Set<ModuleReference> modules;
122
123 // maps module name to module reference
124 private final Map<String, ModuleReference> nameToModule;
125
126 // module name to hashes
127 private final Map<String, byte[]> hashes;
128
129 private SystemModuleFinder() {
130 String[] names = moduleNames();
131 int n = names.length;
132 moduleCount.add(n);
133
134 // fastpath is enabled by default.
135 // It can be disabled for troubleshooting purpose.
136 boolean disabled =
137 System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
138
139 ModuleDescriptor[] descriptors;
140 ModuleHashes[] recordedHashes;
141 ModuleResolution[] moduleResolutions;
142
143 // fast loading of ModuleDescriptor of system modules
144 if (isFastPathSupported() && !disabled) {
145 descriptors = SystemModules.descriptors();
146 recordedHashes = SystemModules.hashes();
147 moduleResolutions = SystemModules.moduleResolutions();
148 } else {
149 // if fast loading of ModuleDescriptors is disabled
150 // fallback to read module-info.class
151 descriptors = new ModuleDescriptor[n];
152 recordedHashes = new ModuleHashes[n];
153 moduleResolutions = new ModuleResolution[n];
154 for (int i = 0; i < names.length; i++) {
155 String mn = names[i];
156 ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
157 ModuleInfo.Attributes attrs =
158 ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
159 descriptors[i] = attrs.descriptor();
160 recordedHashes[i] = attrs.recordedHashes();
161 moduleResolutions[i] = attrs.moduleResolution();
162 }
163 }
164
165 Map<String, byte[]> hashes = null;
166 boolean secondSeen = false;
167 // record the hashes to build HashSupplier
168 for (ModuleHashes mh : recordedHashes) {
169 if (mh != null) {
170 // if only one module contain ModuleHashes, use it
171 if (hashes == null) {
172 hashes = mh.hashes();
173 } else {
274 sm.checkPermission(uc.getPermission());
275 } catch (IOException ioe) {
276 throw new UncheckedIOException(ioe);
277 }
278 }
279 }
280
281 ImageModuleReader(String module, URI uri) {
282 checkPermissionToConnect(uri);
283 this.module = module;
284 }
285
286 /**
287 * Returns the ImageLocation for the given resource, {@code null}
288 * if not found.
289 */
290 private ImageLocation findImageLocation(String name) throws IOException {
291 Objects.requireNonNull(name);
292 if (closed)
293 throw new IOException("ModuleReader is closed");
294 if (imageReader != null) {
295 return imageReader.findLocation(module, name);
296 } else {
297 // not an images build
298 return null;
299 }
300 }
301
302 @Override
303 public Optional<URI> find(String name) throws IOException {
304 ImageLocation location = findImageLocation(name);
305 if (location != null) {
306 URI u = URI.create("jrt:/" + module + "/" + name);
307 return Optional.of(u);
308 } else {
309 return Optional.empty();
310 }
311 }
312
313 @Override
314 public Optional<InputStream> open(String name) throws IOException {
315 return read(name).map(this::toInputStream);
316 }
317
318 private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
319 try {
320 int rem = bb.remaining();
321 byte[] bytes = new byte[rem];
322 bb.get(bytes);
323 return new ByteArrayInputStream(bytes);
324 } finally {
325 release(bb);
326 }
327 }
328
329 @Override
330 public Optional<ByteBuffer> read(String name) throws IOException {
331 ImageLocation location = findImageLocation(name);
332 if (location != null) {
333 return Optional.of(imageReader.getResourceBuffer(location));
334 } else {
335 return Optional.empty();
336 }
337 }
338
339 @Override
340 public void release(ByteBuffer bb) {
341 Objects.requireNonNull(bb);
342 ImageReader.releaseByteBuffer(bb);
343 }
344
345 @Override
346 public Stream<String> list() throws IOException {
347 if (closed)
348 throw new IOException("ModuleReader is closed");
349
350 Spliterator<String> s = new ModuleContentSpliterator(module);
351 return StreamSupport.stream(s, false);
352 }
353
355 public void close() {
356 // nothing else to do
357 closed = true;
358 }
359 }
360
361 /**
362 * A Spliterator for traversing the resources of a module linked into the
363 * run-time image.
364 */
365 static class ModuleContentSpliterator implements Spliterator<String> {
366 final String moduleRoot;
367 final Deque<ImageReader.Node> stack;
368 Iterator<ImageReader.Node> iterator;
369
370 ModuleContentSpliterator(String module) throws IOException {
371 moduleRoot = "/modules/" + module;
372 stack = new ArrayDeque<>();
373
374 // push the root node to the stack to get started
375 ImageReader.Node dir = imageReader.findNode(moduleRoot);
376 if (dir == null || !dir.isDirectory())
377 throw new IOException(moduleRoot + " not a directory");
378 stack.push(dir);
379 iterator = Collections.emptyIterator();
380 }
381
382 /**
383 * Returns the name of the next non-directory node or {@code null} if
384 * there are no remaining nodes to visit.
385 */
386 private String next() throws IOException {
387 for (;;) {
388 while (iterator.hasNext()) {
389 ImageReader.Node node = iterator.next();
390 String name = node.getName();
391 if (node.isDirectory()) {
392 // build node
393 ImageReader.Node dir = imageReader.findNode(name);
394 assert dir.isDirectory();
395 stack.push(dir);
396 } else {
397 // strip /modules/$MODULE/ prefix
398 return name.substring(moduleRoot.length() + 1);
399 }
400 }
401
402 if (stack.isEmpty()) {
403 return null;
404 } else {
405 ImageReader.Node dir = stack.poll();
406 assert dir.isDirectory();
407 iterator = dir.getChildren().iterator();
408 }
409 }
410 }
411
412 @Override
413 public boolean tryAdvance(Consumer<? super String> action) {
|
63 /**
64 * A {@code ModuleFinder} that finds modules that are linked into the
65 * run-time image.
66 *
67 * The modules linked into the run-time image are assumed to have the
68 * Packages attribute.
69 */
70
71 public class SystemModuleFinder implements ModuleFinder {
72
73 private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
74
75 private static final PerfCounter initTime
76 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
77 private static final PerfCounter moduleCount
78 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
79 private static final PerfCounter packageCount
80 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
81 private static final PerfCounter exportsCount
82 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
83
84 // singleton finder to find modules in the run-time images
85 private static final SystemModuleFinder INSTANCE;
86
87 public static SystemModuleFinder getInstance() {
88 return INSTANCE;
89 }
90
91 /**
92 * For now, the module references are created eagerly on the assumption
93 * that service binding will require all modules to be located.
94 */
95 static {
96 long t0 = System.nanoTime();
97
98 INSTANCE = new SystemModuleFinder();
99
100 initTime.addElapsedTimeFrom(t0);
101 }
102
103 /**
104 * Holder class for the ImageReader
105 */
106 private static class SystemImage {
107 static final ImageReader READER;
108 static {
109 long t0 = System.nanoTime();
110 READER = ImageReaderFactory.getImageReader();
111 initTime.addElapsedTimeFrom(t0);
112 }
113
114 static ImageReader reader() {
115 return READER;
116 }
117 }
118
119 private static boolean isFastPathSupported() {
120 return SystemModules.MODULE_NAMES.length > 0;
121 }
122
123 private static String[] moduleNames() {
124 if (isFastPathSupported())
125 // module names recorded at link time
126 return SystemModules.MODULE_NAMES;
127
128 // this happens when java.base is patched with java.base
129 // from an exploded image
130 return SystemImage.reader().getModuleNames();
131 }
132
133 // the set of modules in the run-time image
134 private final Set<ModuleReference> modules;
135
136 // maps module name to module reference
137 private final Map<String, ModuleReference> nameToModule;
138
139 // module name to hashes
140 private final Map<String, byte[]> hashes;
141
142 private SystemModuleFinder() {
143 String[] names = moduleNames();
144 int n = names.length;
145 moduleCount.add(n);
146
147 // fastpath is enabled by default.
148 // It can be disabled for troubleshooting purpose.
149 boolean disabled =
150 System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
151
152 ModuleDescriptor[] descriptors;
153 ModuleHashes[] recordedHashes;
154 ModuleResolution[] moduleResolutions;
155
156 // fast loading of ModuleDescriptor of system modules
157 if (isFastPathSupported() && !disabled) {
158 descriptors = SystemModules.descriptors();
159 recordedHashes = SystemModules.hashes();
160 moduleResolutions = SystemModules.moduleResolutions();
161 } else {
162 // if fast loading of ModuleDescriptors is disabled
163 // fallback to read module-info.class
164 descriptors = new ModuleDescriptor[n];
165 recordedHashes = new ModuleHashes[n];
166 moduleResolutions = new ModuleResolution[n];
167 ImageReader imageReader = SystemImage.reader();
168 for (int i = 0; i < names.length; i++) {
169 String mn = names[i];
170 ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
171 ModuleInfo.Attributes attrs =
172 ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
173 descriptors[i] = attrs.descriptor();
174 recordedHashes[i] = attrs.recordedHashes();
175 moduleResolutions[i] = attrs.moduleResolution();
176 }
177 }
178
179 Map<String, byte[]> hashes = null;
180 boolean secondSeen = false;
181 // record the hashes to build HashSupplier
182 for (ModuleHashes mh : recordedHashes) {
183 if (mh != null) {
184 // if only one module contain ModuleHashes, use it
185 if (hashes == null) {
186 hashes = mh.hashes();
187 } else {
288 sm.checkPermission(uc.getPermission());
289 } catch (IOException ioe) {
290 throw new UncheckedIOException(ioe);
291 }
292 }
293 }
294
295 ImageModuleReader(String module, URI uri) {
296 checkPermissionToConnect(uri);
297 this.module = module;
298 }
299
300 /**
301 * Returns the ImageLocation for the given resource, {@code null}
302 * if not found.
303 */
304 private ImageLocation findImageLocation(String name) throws IOException {
305 Objects.requireNonNull(name);
306 if (closed)
307 throw new IOException("ModuleReader is closed");
308 ImageReader imageReader = SystemImage.reader();
309 if (imageReader != null) {
310 return imageReader.findLocation(module, name);
311 } else {
312 // not an images build
313 return null;
314 }
315 }
316
317 @Override
318 public Optional<URI> find(String name) throws IOException {
319 ImageLocation location = findImageLocation(name);
320 if (location != null) {
321 URI u = URI.create("jrt:/" + module + "/" + name);
322 return Optional.of(u);
323 } else {
324 return Optional.empty();
325 }
326 }
327
328 @Override
329 public Optional<InputStream> open(String name) throws IOException {
330 return read(name).map(this::toInputStream);
331 }
332
333 private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
334 try {
335 int rem = bb.remaining();
336 byte[] bytes = new byte[rem];
337 bb.get(bytes);
338 return new ByteArrayInputStream(bytes);
339 } finally {
340 release(bb);
341 }
342 }
343
344 @Override
345 public Optional<ByteBuffer> read(String name) throws IOException {
346 ImageLocation location = findImageLocation(name);
347 if (location != null) {
348 return Optional.of(SystemImage.reader().getResourceBuffer(location));
349 } else {
350 return Optional.empty();
351 }
352 }
353
354 @Override
355 public void release(ByteBuffer bb) {
356 Objects.requireNonNull(bb);
357 ImageReader.releaseByteBuffer(bb);
358 }
359
360 @Override
361 public Stream<String> list() throws IOException {
362 if (closed)
363 throw new IOException("ModuleReader is closed");
364
365 Spliterator<String> s = new ModuleContentSpliterator(module);
366 return StreamSupport.stream(s, false);
367 }
368
370 public void close() {
371 // nothing else to do
372 closed = true;
373 }
374 }
375
376 /**
377 * A Spliterator for traversing the resources of a module linked into the
378 * run-time image.
379 */
380 static class ModuleContentSpliterator implements Spliterator<String> {
381 final String moduleRoot;
382 final Deque<ImageReader.Node> stack;
383 Iterator<ImageReader.Node> iterator;
384
385 ModuleContentSpliterator(String module) throws IOException {
386 moduleRoot = "/modules/" + module;
387 stack = new ArrayDeque<>();
388
389 // push the root node to the stack to get started
390 ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
391 if (dir == null || !dir.isDirectory())
392 throw new IOException(moduleRoot + " not a directory");
393 stack.push(dir);
394 iterator = Collections.emptyIterator();
395 }
396
397 /**
398 * Returns the name of the next non-directory node or {@code null} if
399 * there are no remaining nodes to visit.
400 */
401 private String next() throws IOException {
402 for (;;) {
403 while (iterator.hasNext()) {
404 ImageReader.Node node = iterator.next();
405 String name = node.getName();
406 if (node.isDirectory()) {
407 // build node
408 ImageReader.Node dir = SystemImage.reader().findNode(name);
409 assert dir.isDirectory();
410 stack.push(dir);
411 } else {
412 // strip /modules/$MODULE/ prefix
413 return name.substring(moduleRoot.length() + 1);
414 }
415 }
416
417 if (stack.isEmpty()) {
418 return null;
419 } else {
420 ImageReader.Node dir = stack.poll();
421 assert dir.isDirectory();
422 iterator = dir.getChildren().iterator();
423 }
424 }
425 }
426
427 @Override
428 public boolean tryAdvance(Consumer<? super String> action) {
|