< prev index next >

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

Print this page




  41 import java.nio.file.Path;
  42 import java.nio.file.Paths;
  43 import java.util.ArrayList;
  44 import java.util.Collections;
  45 import java.util.HashMap;
  46 import java.util.HashSet;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Optional;
  50 import java.util.Set;
  51 import java.util.jar.JarEntry;
  52 import java.util.jar.JarFile;
  53 
  54 import jdk.internal.loader.Resource;
  55 import jdk.internal.misc.JavaLangModuleAccess;
  56 import jdk.internal.misc.SharedSecrets;
  57 import sun.net.www.ParseUtil;
  58 
  59 
  60 /**
  61  * Provides support for patching modules in the boot layer with -Xpatch.
  62  */
  63 
  64 public final class ModulePatcher {
  65 
  66     private static final JavaLangModuleAccess JLMA
  67         = SharedSecrets.getJavaLangModuleAccess();
  68 
  69     // the prefix of the system properties that encode the value of -Xpatch
  70     private static final String PATCH_PROPERTY_PREFIX = "jdk.launcher.patch.";
  71 
  72     // module name -> sequence of patches (directories or JAR files)
  73     private static final Map<String, List<Path>> PATCH_MAP = decodeProperties();
  74 
  75     private ModulePatcher() { }
  76 
  77 
  78     /**
  79      * Decodes the values of -Xpatch options, returning a Map of module name to
  80      * list of file paths.
  81      *
  82      * @throws IllegalArgumentException if the the module name is missing or
  83      *         -Xpatch is used more than once to patch the same module
  84      */
  85     private static Map<String, List<Path>> decodeProperties() {
  86 
  87         int index = 0;
  88         String value = System.getProperty(PATCH_PROPERTY_PREFIX + index);
  89         if (value == null)
  90             return Collections.emptyMap();  // -Xpatch not specified
  91 
  92         Map<String, List<Path>> map = new HashMap<>();
  93         while (value != null) {
  94 
  95             // <module>=<file>(:<file>)*
  96 
  97             int pos = value.indexOf('=');
  98             if (pos == -1)
  99                 throwIAE("Unable to parse: " + value);
 100             if (pos == 0)
 101                 throwIAE("Missing module name: " + value);
 102 
 103             String mn = value.substring(0, pos);
 104             List<Path> list = map.get(mn);
 105             if (list != null)
 106                 throwIAE("Module " + mn + " specified more than once");
 107             list = new ArrayList<>();
 108             map.put(mn, list);
 109 
 110             String paths = value.substring(pos+1);
 111             for (String path : paths.split(File.pathSeparator)) {
 112                 if (!path.isEmpty()) {
 113                     list.add(Paths.get(path));
 114                 }
 115             }
 116 
 117             index++;
 118             value = System.getProperty(PATCH_PROPERTY_PREFIX + index);
 119         }
 120 
 121         return map;
 122     }
 123 
 124 
 125     /**








 126      * Returns a module reference that interposes on the given module if
 127      * needed. If there are no patches for the given module then the module
 128      * reference is simply returned. Otherwise the patches for the module
 129      * are scanned (to find any new concealed packages) and a new module
 130      * reference is returned.
 131      *
 132      * @throws UncheckedIOException if an I/O error is detected
 133      */
 134     public static ModuleReference interposeIfNeeded(ModuleReference mref) {
 135 
 136         ModuleDescriptor descriptor = mref.descriptor();
 137         String mn = descriptor.name();
 138 
 139         // if there are no patches for the module then nothing to do
 140         List<Path> paths = PATCH_MAP.get(mn);
 141         if (paths == null)
 142             return mref;
 143 
 144 
 145         // scan the JAR file or directory tree to get the set of packages


 520                 }
 521             };
 522         }
 523     }
 524 
 525 
 526     /**
 527      * Derives a package name from a file path to a .class file.
 528      */
 529     private static String toPackageName(Path top, Path file) {
 530         Path entry = top.relativize(file);
 531         Path parent = entry.getParent();
 532         if (parent == null) {
 533             return warnUnnamedPackage(top, entry.toString());
 534         } else {
 535             return parent.toString().replace(File.separatorChar, '.');
 536         }
 537     }
 538 
 539     /**







 540      * Derives a package name from the name of an entry in a JAR file.
 541      */
 542     private static String toPackageName(Path file, JarEntry entry) {
 543         String name = entry.getName();
 544         int index = name.lastIndexOf("/");
 545         if (index == -1) {
 546             return warnUnnamedPackage(file, name);
 547         } else {
 548             return name.substring(0, index).replace('/', '.');
 549         }
 550     }
 551 
 552     private static String warnUnnamedPackage(Path file, String e) {
 553         System.err.println("WARNING: " + e + " not allowed in patch: " + file);
 554         return "";
 555     }
 556 
 557     private static void throwIAE(String msg) {
 558         throw new IllegalArgumentException(msg);
 559     }


  41 import java.nio.file.Path;
  42 import java.nio.file.Paths;
  43 import java.util.ArrayList;
  44 import java.util.Collections;
  45 import java.util.HashMap;
  46 import java.util.HashSet;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Optional;
  50 import java.util.Set;
  51 import java.util.jar.JarEntry;
  52 import java.util.jar.JarFile;
  53 
  54 import jdk.internal.loader.Resource;
  55 import jdk.internal.misc.JavaLangModuleAccess;
  56 import jdk.internal.misc.SharedSecrets;
  57 import sun.net.www.ParseUtil;
  58 
  59 
  60 /**
  61  * Provides support for patching modules in the boot layer with --patch-module.
  62  */
  63 
  64 public final class ModulePatcher {
  65 
  66     private static final JavaLangModuleAccess JLMA
  67         = SharedSecrets.getJavaLangModuleAccess();
  68 
  69     // the prefix of the system properties that encode the value of --patch-module
  70     private static final String PATCH_PROPERTY_PREFIX = "jdk.module.patch.";
  71 
  72     // module name -> sequence of patches (directories or JAR files)
  73     private static final Map<String, List<Path>> PATCH_MAP = decodeProperties();
  74 
  75     private ModulePatcher() { }
  76 

  77     /**
  78      * Decodes the values of --patch-module options, returning a Map of module
  79      * name to list of file paths.
  80      *
  81      * @throws IllegalArgumentException if the the module name is missing or
  82      *         --patch-module is used more than once to patch the same module
  83      */
  84     private static Map<String, List<Path>> decodeProperties() {
  85 
  86         int index = 0;
  87         String value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
  88         if (value == null)
  89             return Collections.emptyMap();  // --patch-module not specified
  90 
  91         Map<String, List<Path>> map = new HashMap<>();
  92         while (value != null) {
  93 
  94             // <module>=<file>(:<file>)*
  95 
  96             int pos = value.indexOf('=');
  97             if (pos == -1)
  98                 throwIAE("Unable to parse: " + value);
  99             if (pos == 0)
 100                 throwIAE("Missing module name: " + value);
 101 
 102             String mn = value.substring(0, pos);
 103             List<Path> list = map.get(mn);
 104             if (list != null)
 105                 throwIAE("Module " + mn + " specified more than once");
 106             list = new ArrayList<>();
 107             map.put(mn, list);
 108 
 109             String paths = value.substring(pos+1);
 110             for (String path : paths.split(File.pathSeparator)) {
 111                 if (!path.isEmpty()) {
 112                     list.add(Paths.get(path));
 113                 }
 114             }
 115 
 116             index++;
 117             value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
 118         }
 119 
 120         return map;
 121     }
 122 
 123 
 124     /**
 125      * Returns {@code true} is --patch-module is specified to patch modules
 126      * in the boot layer.
 127      */
 128     static boolean isBootLayerPatched() {
 129         return !PATCH_MAP.isEmpty();
 130     }
 131 
 132     /**
 133      * Returns a module reference that interposes on the given module if
 134      * needed. If there are no patches for the given module then the module
 135      * reference is simply returned. Otherwise the patches for the module
 136      * are scanned (to find any new concealed packages) and a new module
 137      * reference is returned.
 138      *
 139      * @throws UncheckedIOException if an I/O error is detected
 140      */
 141     public static ModuleReference interposeIfNeeded(ModuleReference mref) {
 142 
 143         ModuleDescriptor descriptor = mref.descriptor();
 144         String mn = descriptor.name();
 145 
 146         // if there are no patches for the module then nothing to do
 147         List<Path> paths = PATCH_MAP.get(mn);
 148         if (paths == null)
 149             return mref;
 150 
 151 
 152         // scan the JAR file or directory tree to get the set of packages


 527                 }
 528             };
 529         }
 530     }
 531 
 532 
 533     /**
 534      * Derives a package name from a file path to a .class file.
 535      */
 536     private static String toPackageName(Path top, Path file) {
 537         Path entry = top.relativize(file);
 538         Path parent = entry.getParent();
 539         if (parent == null) {
 540             return warnUnnamedPackage(top, entry.toString());
 541         } else {
 542             return parent.toString().replace(File.separatorChar, '.');
 543         }
 544     }
 545 
 546     /**
 547      * Gets and remove the named system property
 548      */
 549     private static String getAndRemoveProperty(String key) {
 550         return (String)System.getProperties().remove(key);
 551     }
 552 
 553     /**
 554      * Derives a package name from the name of an entry in a JAR file.
 555      */
 556     private static String toPackageName(Path file, JarEntry entry) {
 557         String name = entry.getName();
 558         int index = name.lastIndexOf("/");
 559         if (index == -1) {
 560             return warnUnnamedPackage(file, name);
 561         } else {
 562             return name.substring(0, index).replace('/', '.');
 563         }
 564     }
 565 
 566     private static String warnUnnamedPackage(Path file, String e) {
 567         System.err.println("WARNING: " + e + " not allowed in patch: " + file);
 568         return "";
 569     }
 570 
 571     private static void throwIAE(String msg) {
 572         throw new IllegalArgumentException(msg);
 573     }
< prev index next >