< prev index next >

src/java.base/share/classes/jdk/internal/jimage/ImageReader.java

Print this page

120     }
121 
122     private void requireOpen() {
123         if (closed) {
124             throw new IllegalStateException("image file closed");
125         }
126     }
127 
128     /**
129      * Finds the node with the given name.
130      *
131      * @param name a node name of the form {@code "/modules/<module>/...} or
132      *     {@code "/packages/<package>/...}.
133      * @return a node representing a resource, directory or symbolic link.
134      */
135     public Node findNode(String name) throws IOException {
136         ensureOpen();
137         return reader.findNode(name);
138     }
139 







































140     /**
141      * Returns a copy of the content of a resource node. The buffer returned by
142      * this method is not cached by the node, and each call returns a new array
143      * instance.
144      *
145      * @throws IOException if the content cannot be returned (including if the
146      * given node is not a resource node).
147      */
148     public byte[] getResource(Node node) throws IOException {
149         ensureOpen();
150         return reader.getResource(node);
151     }
152 
153     /**
154      * Releases a (possibly cached) {@link ByteBuffer} obtained via
155      * {@link #getResourceBuffer(Node)}.
156      *
157      * <p>Note that no testing is performed to check whether the buffer about
158      * to be released actually came from a call to {@code getResourceBuffer()}.
159      */

259             synchronized (OPEN_FILES) {
260                 if (!openers.remove(image)) {
261                     throw new IOException("image file already closed");
262                 }
263 
264                 if (openers.isEmpty()) {
265                     close();
266                     nodes.clear();
267 
268                     if (!OPEN_FILES.remove(this.getImagePath(), this)) {
269                         throw new IOException("image file not found in open list");
270                     }
271                 }
272             }
273         }
274 
275         /**
276          * Returns a node with the given name, or null if no resource or directory of
277          * that name exists.
278          *
279          * <p>This is the only public API by which anything outside this class can access
280          * {@code Node} instances either directly, or by resolving symbolic links.
281          *
282          * <p>Note also that there is no reentrant calling back to this method from within
283          * the node handling code.
284          *
285          * @param name an absolute, {@code /}-separated path string, prefixed with either
286          *     "/modules" or "/packages".
287          */
288         synchronized Node findNode(String name) {
289             Node node = nodes.get(name);
290             if (node == null) {
291                 // We cannot get the root paths ("/modules" or "/packages") here
292                 // because those nodes are already in the nodes cache.
293                 if (name.startsWith(MODULES_ROOT + "/")) {



294                     node = buildModulesNode(name);
295                 } else if (name.startsWith(PACKAGES_ROOT + "/")) {
296                     node = buildPackagesNode(name);
297                 }
298                 if (node != null) {
299                     nodes.put(node.getName(), node);
300                 }
301             } else if (!node.isCompleted()) {
302                 // Only directories can be incomplete.
303                 assert node instanceof Directory : "Invalid incomplete node: " + node;
304                 completeDirectory((Directory) node);
305             }
306             assert node == null || node.isCompleted() : "Incomplete node: " + node;
307             return node;
308         }
309 

















































310         /**
311          * Builds a node in the "/modules/..." namespace.
312          *
313          * <p>Called by {@link #findNode(String)} if a {@code /modules/...} node
314          * is not present in the cache.
315          */
316         private Node buildModulesNode(String name) {
317             assert name.startsWith(MODULES_ROOT + "/") : "Invalid module node name: " + name;
318             // Returns null for non-directory resources, since the jimage name does not
319             // start with "/modules" (e.g. "/java.base/java/lang/Object.class").
320             ImageLocation loc = findLocation(name);
321             if (loc != null) {
322                 assert name.equals(loc.getFullName()) : "Mismatched location for directory: " + name;
323                 assert isModulesSubdirectory(loc) : "Invalid modules directory: " + name;
324                 return completeModuleDirectory(newDirectory(name), loc);
325             }
326             // Now try the non-prefixed resource name, but be careful to avoid false
327             // positives for names like "/modules/modules/xxx" which could return a
328             // location of a directory entry.
329             loc = findLocation(name.substring(MODULES_ROOT.length()));

120     }
121 
122     private void requireOpen() {
123         if (closed) {
124             throw new IllegalStateException("image file closed");
125         }
126     }
127 
128     /**
129      * Finds the node with the given name.
130      *
131      * @param name a node name of the form {@code "/modules/<module>/...} or
132      *     {@code "/packages/<package>/...}.
133      * @return a node representing a resource, directory or symbolic link.
134      */
135     public Node findNode(String name) throws IOException {
136         ensureOpen();
137         return reader.findNode(name);
138     }
139 
140     /**
141      * Returns a resource node in the given module, or null if no resource of
142      * that name exists.
143      *
144      * <p>This is equivalent to:
145      * <pre>{@code
146      * findNode("/modules/" + moduleName + "/" + resourcePath)
147      * }</pre>
148      * but more performant, and returns {@code null} for directories.
149      *
150      * @param moduleName The module name of the requested resource.
151      * @param resourcePath Trailing module-relative resource path, not starting
152      *     with {@code '/'}.
153      */
154     public Node findResourceNode(String moduleName, String resourcePath)
155             throws IOException {
156         ensureOpen();
157         return reader.findResourceNode(moduleName, resourcePath);
158     }
159 
160     /**
161      * Returns whether a resource exists in the given module.
162      *
163      * <p>This is equivalent to:
164      * <pre>{@code
165      * findResourceNode(moduleName, resourcePath) != null
166      * }</pre>
167      * but more performant, and will not create or cache new nodes.
168      *
169      * @param moduleName The module name of the resource being tested for.
170      * @param resourcePath Trailing module-relative resource path, not starting
171      *     with {@code '/'}.
172      */
173     public boolean containsResource(String moduleName, String resourcePath)
174             throws IOException {
175         ensureOpen();
176         return reader.containsResource(moduleName, resourcePath);
177     }
178 
179     /**
180      * Returns a copy of the content of a resource node. The buffer returned by
181      * this method is not cached by the node, and each call returns a new array
182      * instance.
183      *
184      * @throws IOException if the content cannot be returned (including if the
185      * given node is not a resource node).
186      */
187     public byte[] getResource(Node node) throws IOException {
188         ensureOpen();
189         return reader.getResource(node);
190     }
191 
192     /**
193      * Releases a (possibly cached) {@link ByteBuffer} obtained via
194      * {@link #getResourceBuffer(Node)}.
195      *
196      * <p>Note that no testing is performed to check whether the buffer about
197      * to be released actually came from a call to {@code getResourceBuffer()}.
198      */

298             synchronized (OPEN_FILES) {
299                 if (!openers.remove(image)) {
300                     throw new IOException("image file already closed");
301                 }
302 
303                 if (openers.isEmpty()) {
304                     close();
305                     nodes.clear();
306 
307                     if (!OPEN_FILES.remove(this.getImagePath(), this)) {
308                         throw new IOException("image file not found in open list");
309                     }
310                 }
311             }
312         }
313 
314         /**
315          * Returns a node with the given name, or null if no resource or directory of
316          * that name exists.
317          *
318          * <p>Note that there is no reentrant calling back to this method from within



319          * the node handling code.
320          *
321          * @param name an absolute, {@code /}-separated path string, prefixed with either
322          *     "/modules" or "/packages".
323          */
324         synchronized Node findNode(String name) {
325             Node node = nodes.get(name);
326             if (node == null) {
327                 // We cannot get the root paths ("/modules" or "/packages") here
328                 // because those nodes are already in the nodes cache.
329                 if (name.startsWith(MODULES_ROOT + "/")) {
330                     // This may perform two lookups, one for a directory (in
331                     // "/modules/...") and one for a non-prefixed resource
332                     // (with "/modules" removed).
333                     node = buildModulesNode(name);
334                 } else if (name.startsWith(PACKAGES_ROOT + "/")) {
335                     node = buildPackagesNode(name);
336                 }
337                 if (node != null) {
338                     nodes.put(node.getName(), node);
339                 }
340             } else if (!node.isCompleted()) {
341                 // Only directories can be incomplete.
342                 assert node instanceof Directory : "Invalid incomplete node: " + node;
343                 completeDirectory((Directory) node);
344             }
345             assert node == null || node.isCompleted() : "Incomplete node: " + node;
346             return node;
347         }
348 
349         /**
350          * Returns a resource node in the given module, or null if no resource of
351          * that name exists.
352          *
353          * <p>Note that there is no reentrant calling back to this method from within
354          * the node handling code.
355          */
356         Node findResourceNode(String moduleName, String resourcePath) {
357             // Unlike findNode(), this method makes only one lookup in the
358             // underlying jimage, but can only reliably return resource nodes.
359             if (moduleName.indexOf('/') >= 0) {
360                 throw new IllegalArgumentException("invalid module name: " + moduleName);
361             }
362             String nodeName = MODULES_ROOT + "/" + moduleName + "/" + resourcePath;
363             // Synchronize as tightly as possible to reduce locking contention.
364             synchronized (this) {
365                 Node node = nodes.get(nodeName);
366                 if (node == null) {
367                     ImageLocation loc = findLocation(moduleName, resourcePath);
368                     if (loc != null && isResource(loc)) {
369                         node = newResource(nodeName, loc);
370                         nodes.put(node.getName(), node);
371                     }
372                     return node;
373                 } else {
374                     return node.isResource() ? node : null;
375                 }
376             }
377         }
378 
379         /**
380          * Returns whether a resource exists in the given module.
381          *
382          * <p>This method is expected to be called frequently for resources
383          * which do not exist in the given module (e.g. as part of classpath
384          * search). As such, it skips checking the nodes cache and only checks
385          * for an entry in the jimage file, as this is faster if the resource
386          * is not present. This also means it doesn't need synchronization.
387          */
388         boolean containsResource(String moduleName, String resourcePath) {
389             if (moduleName.indexOf('/') >= 0) {
390                 throw new IllegalArgumentException("invalid module name: " + moduleName);
391             }
392             // If the given module name is 'modules', then 'isResource()'
393             // returns false to prevent false positives.
394             ImageLocation loc = findLocation(moduleName, resourcePath);
395             return loc != null && isResource(loc);
396         }
397 
398         /**
399          * Builds a node in the "/modules/..." namespace.
400          *
401          * <p>Called by {@link #findNode(String)} if a {@code /modules/...} node
402          * is not present in the cache.
403          */
404         private Node buildModulesNode(String name) {
405             assert name.startsWith(MODULES_ROOT + "/") : "Invalid module node name: " + name;
406             // Returns null for non-directory resources, since the jimage name does not
407             // start with "/modules" (e.g. "/java.base/java/lang/Object.class").
408             ImageLocation loc = findLocation(name);
409             if (loc != null) {
410                 assert name.equals(loc.getFullName()) : "Mismatched location for directory: " + name;
411                 assert isModulesSubdirectory(loc) : "Invalid modules directory: " + name;
412                 return completeModuleDirectory(newDirectory(name), loc);
413             }
414             // Now try the non-prefixed resource name, but be careful to avoid false
415             // positives for names like "/modules/modules/xxx" which could return a
416             // location of a directory entry.
417             loc = findLocation(name.substring(MODULES_ROOT.length()));
< prev index next >