< prev index next >

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

Print this page

        

@@ -20,64 +20,106 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package jdk.internal.loader;
+package jdk.internal.module;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-
-import jdk.internal.module.Checks;
+import java.nio.file.attribute.BasicFileAttributes;
 
 /**
- * Helper class for Class#getResource, Module#getResourceAsStream, and other
- * methods that locate a resource in a module.
+ * A helper class to support working with resources in modules. Also provides
+ * support for translating resource names to file paths.
  */
-public final class ResourceHelper {
-    private ResourceHelper() { }
+public final class Resources {
+    private Resources() { }
 
     /**
-     * Returns the <em>package name</em> for a resource or the empty package if
-     * the resource name does not contain a slash.
+     * Return true if a resource can be encapsulated. Resource with names
+     * ending in ".class" or "/" cannot be encapsulated. Resource names
+     * that map to a legal package name can be encapsulated.
      */
-    public static String getPackageName(String name) {
-        int index = name.lastIndexOf('/');
-        if (index != -1) {
-            return name.substring(0, index).replace("/", ".");
+    public static boolean canEncapsulate(String name) {
+        int len = name.length();
+        if (len > 6 && name.endsWith(".class")) {
+            return false;
         } else {
-            return "";
+            return Checks.isPackageName(toPackageName(name));
         }
     }
 
     /**
-     * Returns true if the resource is a <em>simple resource</em>. Simple
-     * resources can never be encapsulated. Resources ending in "{@code .class}"
-     * or where the package name is not a legal package name can not be
-     * encapsulated.
+     * Derive a <em>package name</em> for a resource. The package name
+     * returned by this method may not be a legal package name. This method
+     * returns null if the the resource name ends with a "/" (a directory)
+     * or the resource name does not contain a "/".
      */
-    public static boolean isSimpleResource(String name) {
-        int len = name.length();
-        if (len > 6 && name.endsWith(".class")) {
-            return true;
+    public static String toPackageName(String name) {
+        int index = name.lastIndexOf('/');
+        if (index == -1 || index == name.length()-1) {
+            return "";
+        } else {
+            return name.substring(0, index).replace("/", ".");
         }
-        if (!Checks.isPackageName(getPackageName(name))) {
-            return true;
         }
-        return false;
+
+    /**
+     * Returns a resource name corresponding to the relative file path
+     * between {@code dir} and {@code file}. If the file is a directory
+     * then the name will end with a  "/", except the top-level directory
+     * where the empty string is returned.
+     */
+    public static String toResourceName(Path dir, Path file) {
+        String s = dir.relativize(file)
+                      .toString()
+                      .replace(File.separatorChar, '/');
+        if (s.length() > 0 && Files.isDirectory(file))
+            s += "/";
+        return s;
     }
 
     /**
-     * Converts a resource name to a file path. Returns {@code null} if the
-     * resource name cannot be converted into a file path. Resource names
-     * with empty elements, or elements that are "." or ".." are rejected,
-     * as is a resource name that translates to a file path with a root
-     * component.
+     * Returns a file path to a resource in a file tree. If the resource
+     * name has a trailing "/" then the file path will locate a directory.
+     * Returns {@code null} if the resource does not map to a file in the
+     * tree file.
+     */
+    public static Path toFilePath(Path dir, String name) throws IOException {
+        boolean expectDirectory = name.endsWith("/");
+        if (expectDirectory) {
+            name = name.substring(0, name.length() - 1);  // drop trailing "/"
+        }
+        Path path = toSafeFilePath(name);
+        if (path != null) {
+            Path file = dir.resolve(path);
+            try {
+                BasicFileAttributes attrs;
+                attrs = Files.readAttributes(file, BasicFileAttributes.class);
+                if (attrs.isDirectory()
+                    || (!attrs.isDirectory() && !expectDirectory))
+                    return file;
+            } catch (NoSuchFileException ignore) { }
+        }
+        return null;
+    }
+
+    /**
+     * Map a resource name to a "safe" file path. Returns {@code null} if
+     * the resource name cannot be converted into a "safe" file path.
+     *
+     * Resource names with empty elements, or elements that are "." or ".."
+     * are rejected, as are resource names that translates to a file path
+     * with a root component.
      */
-    public static Path toFilePath(String name) {
-        // scan the resource name to eagerly reject obviously invalid names
+    private static Path toSafeFilePath(String name) {
+        // scan elements of resource name
         int next;
         int off = 0;
         while ((next = name.indexOf('/', off)) != -1) {
             int len = next - off;
             if (!mayTranslate(name, off, len)) {
< prev index next >