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.InstalledModules; 48 import jdk.internal.module.ModulePatcher; 49 import jdk.internal.perf.PerfCounter; 50 51 /** 52 * A {@code ModuleFinder} that finds modules that are linked into the 53 * run-time image. 54 * 55 * The modules linked into the run-time image are assumed to have the 56 * ConcealedPackages attribute. 57 */ 58 59 class InstalledModuleFinder implements ModuleFinder { 60 61 private static final PerfCounter initTime 62 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); 63 private static final PerfCounter moduleCount 64 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); 65 private static final PerfCounter packageCount 66 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); 67 private static final PerfCounter exportsCount 68 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); 69 // ImageReader used to access all modules in the image 70 private static final ImageReader imageReader; 71 72 // the set of modules in the run-time image 73 private static final Set<ModuleReference> modules; 74 75 // maps module name to module reference 76 private static final Map<String, ModuleReference> nameToModule; 77 78 /** 79 * For now, the module references are created eagerly on the assumption 80 * that service binding will require all modules to be located. 81 */ 82 static { 83 long t0 = System.nanoTime(); 84 imageReader = ImageReaderFactory.getImageReader(); 85 86 String[] moduleNames = InstalledModules.MODULE_NAMES; 87 ModuleDescriptor[] descriptors = null; 88 89 boolean fastLoad = System.getProperty("jdk.installed.modules.disable") == null; 90 if (fastLoad) { 91 // fast loading of ModuleDescriptor of installed modules 92 descriptors = InstalledModules.modules(); 93 } 94 95 int n = moduleNames.length; 96 moduleCount.add(n); 97 98 Set<ModuleReference> mods = new HashSet<>(n); 99 Map<String, ModuleReference> map = new HashMap<>(n); 100 101 for (int i = 0; i < n; i++) { 102 String mn = moduleNames[i]; 103 ModuleDescriptor md; 104 if (fastLoad) { 105 md = descriptors[i]; 106 } else { 107 // fallback to read module-info.class 108 // if fast loading of ModuleDescriptors is disabled 109 ImageLocation location = imageReader.findLocation(mn, "module-info.class"); 110 md = ModuleDescriptor.read(imageReader.getResourceBuffer(location)); 111 } 112 if (!md.name().equals(mn)) 113 throw new InternalError(); 114 115 // create the ModuleReference 116 117 URI uri = URI.create("jrt:/" + mn); 118 119 Supplier<ModuleReader> readerSupplier = new Supplier<>() { 120 @Override 121 public ModuleReader get() { 122 return new ImageModuleReader(mn, uri); 123 } 124 }; 125 126 ModuleReference mref = new ModuleReference(md, uri, readerSupplier); 127 128 // may need a reference to a patched module if -Xpatch specified 129 mref = ModulePatcher.interposeIfNeeded(mref); 130 131 mods.add(mref); 132 map.put(mn, mref); 133 134 // counters 135 packageCount.add(md.packages().size()); 136 exportsCount.add(md.exports().size()); 137 } 138 139 modules = Collections.unmodifiableSet(mods); 140 nameToModule = map; 141 142 initTime.addElapsedTimeFrom(t0); 143 } 144 145 InstalledModuleFinder() { } 146 147 @Override 148 public Optional<ModuleReference> find(String name) { 149 Objects.requireNonNull(name); 150 return Optional.ofNullable(nameToModule.get(name)); 151 } 152 153 @Override 154 public Set<ModuleReference> findAll() { 155 return modules; 156 } 157 158 159 /** 160 * A ModuleReader for reading resources from a module linked into the 161 * run-time image. 162 */ 163 static class ImageModuleReader implements ModuleReader { 164 private final String module; 165 private volatile boolean closed; 166 167 /** 168 * If there is a security manager set then check permission to 169 * connect to the run-time image. 170 */ 171 private static void checkPermissionToConnect(URI uri) { 172 SecurityManager sm = System.getSecurityManager(); 173 if (sm != null) { 174 try { 175 URLConnection uc = uri.toURL().openConnection(); 176 sm.checkPermission(uc.getPermission()); 177 } catch (IOException ioe) { 178 throw new UncheckedIOException(ioe); 179 } 180 } 181 } 182 183 ImageModuleReader(String module, URI uri) { 184 checkPermissionToConnect(uri); 185 this.module = module; 186 } 187 188 /** 189 * Returns the ImageLocation for the given resource, {@code null} 190 * if not found. 191 */ 192 private ImageLocation findImageLocation(String name) throws IOException { 193 if (closed) 194 throw new IOException("ModuleReader is closed"); 195 196 if (imageReader != null) { 197 return imageReader.findLocation(module, name); 198 } else { 199 // not an images build 200 return null; 201 } 202 } 203 204 @Override 205 public Optional<URI> find(String name) throws IOException { 206 ImageLocation location = findImageLocation(name); 207 if (location != null) { 208 URI u = URI.create("jrt:/" + module + "/" + name); 209 return Optional.of(u); 210 } else { 211 return Optional.empty(); 212 } 213 } 214 215 @Override 216 public Optional<InputStream> open(String name) throws IOException { 217 return read(name).map(this::toInputStream); 218 } 219 220 private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer? 221 try { 222 int rem = bb.remaining(); 223 byte[] bytes = new byte[rem]; 224 bb.get(bytes); 225 return new ByteArrayInputStream(bytes); 226 } finally { 227 release(bb); 228 } 229 } 230 231 @Override 232 public Optional<ByteBuffer> read(String name) throws IOException { 233 ImageLocation location = findImageLocation(name); 234 if (location != null) { 235 return Optional.of(imageReader.getResourceBuffer(location)); 236 } else { 237 return Optional.empty(); 238 } 239 } 240 241 @Override 242 public void release(ByteBuffer bb) { 243 ImageReader.releaseByteBuffer(bb); 244 } 245 246 @Override 247 public void close() { 248 // nothing else to do 249 closed = true; 250 } 251 } 252 253 }