1 /* 2 * Copyright (c) 2015, 2016, 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 23 * questions. 24 */ 25 26 package java.lang.module; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.UncheckedIOException; 32 import java.net.URI; 33 import java.net.URLConnection; 34 import java.nio.ByteBuffer; 35 import java.util.Collections; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.Map; 39 import java.util.Objects; 40 import java.util.Optional; 41 import java.util.Set; 42 import java.util.function.Supplier; 43 44 import jdk.internal.jimage.ImageLocation; 45 import jdk.internal.jimage.ImageReader; 46 import jdk.internal.jimage.ImageReaderFactory; 47 import jdk.internal.module.ModuleHashes; 48 import jdk.internal.module.ModuleHashes.HashSupplier; 49 import jdk.internal.module.SystemModules; 50 import jdk.internal.module.ModulePatcher; 51 import jdk.internal.perf.PerfCounter; 52 53 /** 54 * A {@code ModuleFinder} that finds modules that are linked into the 55 * run-time image. 56 * 57 * The modules linked into the run-time image are assumed to have the 58 * ConcealedPackages attribute. 59 */ 60 61 class SystemModuleFinder implements ModuleFinder { 62 63 private static final PerfCounter initTime 64 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); 65 private static final PerfCounter moduleCount 66 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); 67 private static final PerfCounter packageCount 68 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); 69 private static final PerfCounter exportsCount 70 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); 71 // ImageReader used to access all modules in the image 72 private static final ImageReader imageReader; 73 74 // the set of modules in the run-time image 75 private static final Set<ModuleReference> modules; 76 77 // maps module name to module reference 78 private static final Map<String, ModuleReference> nameToModule; 79 80 /** 81 * For now, the module references are created eagerly on the assumption 82 * that service binding will require all modules to be located. 83 */ 84 static { 85 long t0 = System.nanoTime(); 86 imageReader = ImageReaderFactory.getImageReader(); 87 88 String[] names = moduleNames(); 89 ModuleDescriptor[] descriptors = descriptors(names); 90 91 int n = names.length; 92 moduleCount.add(n); 93 94 Set<ModuleReference> mods = new HashSet<>(n); 95 Map<String, ModuleReference> map = new HashMap<>(n); 96 97 for (int i = 0; i < n; i++) { 98 ModuleDescriptor md = descriptors[i]; 99 100 // create the ModuleReference 101 ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i])); 102 103 mods.add(mref); 104 map.put(names[i], mref); 105 106 // counters 107 packageCount.add(md.packages().size()); 108 exportsCount.add(md.exports().size()); 109 } 110 111 modules = Collections.unmodifiableSet(mods); 112 nameToModule = map; 113 114 initTime.addElapsedTimeFrom(t0); 115 } 116 117 /* 118 * Returns an array of ModuleDescriptor of the given module names. 119 * 120 * This obtains ModuleDescriptors from SystemModules class that is generated 121 * from the jlink system-modules plugin. ModuleDescriptors have already 122 * been validated at link time. 123 * 124 * If java.base is patched, or fastpath is disabled for troubleshooting 125 * purpose, it will fall back to find system modules via jrt file system. 126 */ 127 private static ModuleDescriptor[] descriptors(String[] names) { 128 // fastpath is enabled by default. 129 // It can be disabled for troubleshooting purpose. 130 boolean disabled = 131 System.getProperty("jdk.system.module.finder.disabledFastPath") != null; 132 133 // fast loading of ModuleDescriptor of system modules 134 if (isFastPathSupported() && !disabled) 135 return SystemModules.modules(); 136 137 // if fast loading of ModuleDescriptors is disabled 138 // fallback to read module-info.class 139 ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length]; 140 for (int i = 0; i < names.length; i++) { 141 String mn = names[i]; 142 ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); 143 descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc)); 144 145 // add the recorded hashes of tied modules 146 Hashes.add(descriptors[i]); 147 } 148 return descriptors; 149 } 150 151 private static boolean isFastPathSupported() { 152 return SystemModules.MODULE_NAMES.length > 0; 153 } 154 155 private static String[] moduleNames() { 156 if (isFastPathSupported()) 157 // module names recorded at link time 158 return SystemModules.MODULE_NAMES; 159 160 // this happens when java.base is patched with java.base 161 // from an exploded image 162 return imageReader.getModuleNames(); 163 } 164 165 private static ModuleReference toModuleReference(ModuleDescriptor md, 166 HashSupplier hash) 167 { 168 String mn = md.name(); 169 URI uri = URI.create("jrt:/" + mn); 170 171 Supplier<ModuleReader> readerSupplier = new Supplier<>() { 172 @Override 173 public ModuleReader get() { 174 return new ImageModuleReader(mn, uri); 175 } 176 }; 177 178 ModuleReference mref = 179 new ModuleReference(md, uri, readerSupplier, hash); 180 181 // may need a reference to a patched module if --patch-module specified 182 mref = ModulePatcher.interposeIfNeeded(mref); 183 184 return mref; 185 } 186 187 private static HashSupplier hashSupplier(int index, String name) { 188 if (isFastPathSupported()) { 189 return new HashSupplier() { 190 @Override 191 public String generate(String algorithm) { 192 return SystemModules.MODULES_TO_HASH[index]; 193 } 194 }; 195 } else { 196 return Hashes.hashFor(name); 197 } 198 } 199 200 /* 201 * This helper class is only used when SystemModules is patched. 202 * It will get the recorded hashes from module-info.class. 203 */ 204 private static class Hashes { 205 static Map<String, String> hashes = new HashMap<>(); 206 207 static void add(ModuleDescriptor descriptor) { 208 Optional<ModuleHashes> ohashes = descriptor.hashes(); 209 if (ohashes.isPresent()) { 210 hashes.putAll(ohashes.get().hashes()); 211 } 212 } 213 214 static HashSupplier hashFor(String name) { 215 if (!hashes.containsKey(name)) 216 return null; 217 218 return new HashSupplier() { 219 @Override 220 public String generate(String algorithm) { 221 return hashes.get(name); 222 } 223 }; 224 } 225 } 226 227 SystemModuleFinder() { } 228 229 @Override 230 public Optional<ModuleReference> find(String name) { 231 Objects.requireNonNull(name); 232 return Optional.ofNullable(nameToModule.get(name)); 233 } 234 235 @Override 236 public Set<ModuleReference> findAll() { 237 return modules; 238 } 239 240 241 /** 242 * A ModuleReader for reading resources from a module linked into the 243 * run-time image. 244 */ 245 static class ImageModuleReader implements ModuleReader { 246 private final String module; 247 private volatile boolean closed; 248 249 /** 250 * If there is a security manager set then check permission to 251 * connect to the run-time image. 252 */ 253 private static void checkPermissionToConnect(URI uri) { 254 SecurityManager sm = System.getSecurityManager(); 255 if (sm != null) { 256 try { 257 URLConnection uc = uri.toURL().openConnection(); 258 sm.checkPermission(uc.getPermission()); 259 } catch (IOException ioe) { 260 throw new UncheckedIOException(ioe); 261 } 262 } 263 } 264 265 ImageModuleReader(String module, URI uri) { 266 checkPermissionToConnect(uri); 267 this.module = module; 268 } 269 270 /** 271 * Returns the ImageLocation for the given resource, {@code null} 272 * if not found. 273 */ 274 private ImageLocation findImageLocation(String name) throws IOException { 275 Objects.requireNonNull(name); 276 if (closed) 277 throw new IOException("ModuleReader is closed"); 278 if (imageReader != null) { 279 return imageReader.findLocation(module, name); 280 } else { 281 // not an images build 282 return null; 283 } 284 } 285 286 @Override 287 public Optional<URI> find(String name) throws IOException { 288 ImageLocation location = findImageLocation(name); 289 if (location != null) { 290 URI u = URI.create("jrt:/" + module + "/" + name); 291 return Optional.of(u); 292 } else { 293 return Optional.empty(); 294 } 295 } 296 297 @Override 298 public Optional<InputStream> open(String name) throws IOException { 299 return read(name).map(this::toInputStream); 300 } 301 302 private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer? 303 try { 304 int rem = bb.remaining(); 305 byte[] bytes = new byte[rem]; 306 bb.get(bytes); 307 return new ByteArrayInputStream(bytes); 308 } finally { 309 release(bb); 310 } 311 } 312 313 @Override 314 public Optional<ByteBuffer> read(String name) throws IOException { 315 ImageLocation location = findImageLocation(name); 316 if (location != null) { 317 return Optional.of(imageReader.getResourceBuffer(location)); 318 } else { 319 return Optional.empty(); 320 } 321 } 322 323 @Override 324 public void release(ByteBuffer bb) { 325 Objects.requireNonNull(bb); 326 ImageReader.releaseByteBuffer(bb); 327 } 328 329 @Override 330 public void close() { 331 // nothing else to do 332 closed = true; 333 } 334 } 335 336 }