jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModules.java
changeset 31675 d77c79cba81d
parent 31466 3c041fe4cc7d
parent 31674 d60ab1cd78ae
child 31676 1a415610d9dd
equal deleted inserted replaced
31466:3c041fe4cc7d 31675:d77c79cba81d
     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 }