1 /* 2 * Copyright (c) 2014, 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 jdk.internal.jimage; 27 28 import java.io.DataOutputStream; 29 import java.io.IOException; 30 import java.util.Collections; 31 import java.util.HashMap; 32 import java.util.LinkedHashMap; 33 import java.util.LinkedHashSet; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.stream.Collectors; 38 39 import static jdk.internal.jimage.PackageModuleMap.*; 40 41 public class ImageModules { 42 protected final Map<Loader, LoaderModuleData> loaders = new LinkedHashMap<>(); 43 protected final Map<String, Set<String>> localPkgs = new HashMap<>(); 44 45 protected ImageModules() {} 46 47 public ImageModules(Set<String> bootModules, 48 Set<String> extModules, 49 Set<String> appModules) throws IOException { 50 mapModulesToLoader(Loader.BOOT_LOADER, bootModules); 51 mapModulesToLoader(Loader.EXT_LOADER, extModules); 52 mapModulesToLoader(Loader.APP_LOADER, appModules); 53 } 54 55 public Map<String, Set<String>> packages() { 56 return localPkgs; 57 } 58 59 // ## FIXME: should be package-private 60 // When jlink legacy format support is removed, it should 61 // use the package table in the jimage. 62 public void setPackages(String mn, Set<String> pkgs) { 63 localPkgs.put(mn, pkgs); 64 } 65 66 /* 67 * Returns the name of modules mapped to a given class loader in the image 68 */ 69 public Set<String> getModules(Loader type) { 70 if (loaders.containsKey(type)) { 71 return loaders.get(type).modules(); 72 } else { 73 return Collections.emptySet(); 74 } 75 } 76 77 private void mapModulesToLoader(Loader loader, Set<String> modules) { 78 if (modules.isEmpty()) 79 return; 80 81 // put java.base first 82 Set<String> mods = new LinkedHashSet<>(); 83 modules.stream() 84 .filter(m -> m.equals("java.base")) 85 .forEach(mods::add); 86 modules.stream().sorted() 87 .filter(m -> !m.equals("java.base")) 88 .forEach(mods::add); 89 loaders.put(loader, new LoaderModuleData(loader, mods)); 90 } 91 92 enum Loader { 93 BOOT_LOADER(0, "bootmodules"), 94 EXT_LOADER(1, "extmodules"), 95 APP_LOADER(2, "appmodules"); // ## may be more than 1 loader 96 97 final int id; 98 final String name; 99 Loader(int id, String name) { 100 this.id = id; 101 this.name = name; 102 } 103 104 String getName() { 105 return name; 106 } 107 static Loader get(int id) { 108 switch (id) { 109 case 0: return BOOT_LOADER; 110 case 1: return EXT_LOADER; 111 case 2: return APP_LOADER; 112 default: 113 throw new IllegalArgumentException("invalid loader id: " + id); 114 } 115 } 116 public int id() { return id; } 117 } 118 119 public class LoaderModuleData { 120 private final Loader loader; 121 private final Set<String> modules; 122 LoaderModuleData(Loader loader, Set<String> modules) { 123 this.loader = loader; 124 this.modules = Collections.unmodifiableSet(modules); 125 } 126 127 Set<String> modules() { 128 return modules; 129 } 130 Loader loader() { return loader; } 131 } 132 133 ModuleIndex buildModuleIndex(Loader type, BasicImageWriter writer) { 134 return new ModuleIndex(getModules(type), writer); 135 } 136 137 /* 138 * Generate module name table and the package map as resources 139 * in the modular image 140 */ 141 public class ModuleIndex { 142 final Map<String, Integer> moduleOffsets = new LinkedHashMap<>(); 143 final Map<String, List<Integer>> packageOffsets = new HashMap<>(); 144 final int size; 145 public ModuleIndex(Set<String> mods, BasicImageWriter writer) { 146 // module name offsets 147 writer.addLocation(MODULES_ENTRY, 0, 0, mods.size() * 4); 148 long offset = mods.size() * 4; 149 for (String mn : mods) { 150 moduleOffsets.put(mn, writer.addString(mn)); 151 List<Integer> poffsets = localPkgs.get(mn).stream() 152 .map(pn -> pn.replace('.', '/')) 153 .map(writer::addString) 154 .collect(Collectors.toList()); 155 // package name offsets per module 156 String entry = mn + "/" + PACKAGES_ENTRY; 157 int bytes = poffsets.size() * 4; 158 writer.addLocation(entry, offset, 0, bytes); 159 offset += bytes; 160 packageOffsets.put(mn, poffsets); 161 } 162 this.size = (int) offset; 163 } 164 165 void writeTo(DataOutputStream out) throws IOException { 166 for (int moffset : moduleOffsets.values()) { 167 out.writeInt(moffset); 168 } 169 for (String mn : moduleOffsets.keySet()) { 170 for (int poffset : packageOffsets.get(mn)) { 171 out.writeInt(poffset); 172 } 173 } 174 } 175 176 int size() { 177 return size; 178 } 179 } 180 }