1/* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package p4; 25 26import java.io.IOException; 27import java.io.InputStream; 28import java.lang.module.ModuleDescriptor; 29import java.lang.module.ModuleFinder; 30import java.net.URI; 31import java.nio.file.FileSystem; 32import java.nio.file.FileSystems; 33import java.nio.file.Files; 34import java.nio.file.Path; 35import java.util.Collections; 36import java.util.Set; 37 38import jdk.internal.module.ClassFileAttributes; 39import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute; 40import jdk.internal.module.ClassFileConstants; 41import jdk.internal.org.objectweb.asm.Attribute; 42import jdk.internal.org.objectweb.asm.ClassReader; 43import jdk.internal.org.objectweb.asm.ClassVisitor; 44import jdk.internal.org.objectweb.asm.Opcodes; 45 46public class Main { 47 private static boolean hasModuleTarget(InputStream in) throws IOException { 48 ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1]; 49 ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) { 50 @Override 51 public void visitAttribute(Attribute attr) { 52 if (attr instanceof ModuleTargetAttribute) { 53 modTargets[0] = (ModuleTargetAttribute)attr; 54 } 55 } 56 }; 57 58 // prototype of attributes that should be parsed 59 Attribute[] attrs = new Attribute[] { 60 new ModuleTargetAttribute() 61 }; 62 63 // parse module-info.class 64 ClassReader cr = new ClassReader(in); 65 cr.accept(cv, attrs, 0); 66 return modTargets[0] != null && modTargets[0].targetPlatform() != null; 67 } 68 69 private static boolean hasModuleTarget(String modName) throws IOException { 70 FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), 71 Collections.emptyMap()); 72 Path path = fs.getPath("/", "modules", modName, "module-info.class"); 73 try (InputStream in = Files.newInputStream(path)) { 74 return hasModuleTarget(in); 75 } 76 } 77 78 // the system module plugin by default drops ModuleTarget attribute 79 private static boolean expectModuleTarget = false; 80 public static void main(String... args) throws IOException { 81 if (args.length > 0) { 82 if (!args[0].equals("retainModuleTarget")) { 83 throw new IllegalArgumentException(args[0]); 84 } 85 86 expectModuleTarget = true; 87 } 88 89 // java.base is packaged with osName/osArch/osVersion 90 if (! hasModuleTarget("java.base")) { 91 throw new RuntimeException("ModuleTarget absent for java.base"); 92 } 93 94 // verify module-info.class for m1 and m4 95 checkModule("m1", "p1", "p2"); 96 checkModule("m4", "p4"); 97 } 98 99 private static void checkModule(String mn, String... packages) throws IOException { 100 // verify ModuleDescriptor from the runtime module 101 ModuleDescriptor md = ModuleLayer.boot().findModule(mn).get() 102 .getDescriptor(); 103 checkModuleDescriptor(md, packages); 104 105 // verify ModuleDescriptor from module-info.class read from ModuleReader 106 try (InputStream in = ModuleFinder.ofSystem().find(mn).get() 107 .open().open("module-info.class").get()) { 108 checkModuleDescriptor(ModuleDescriptor.read(in), packages); 109 } 110 111 // verify ModuleDescriptor from module-info.class read from jimage 112 FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), 113 Collections.emptyMap()); 114 Path path = fs.getPath("/", "modules", mn, "module-info.class"); 115 checkModuleDescriptor(ModuleDescriptor.read(Files.newInputStream(path)), packages); 116 } 117 118 static void checkModuleDescriptor(ModuleDescriptor md, String... packages) throws IOException { 119 String mainClass = md.name().replace('m', 'p') + ".Main"; 120 if (!md.mainClass().get().equals(mainClass)) { 121 throw new RuntimeException(md.mainClass().toString()); 122 } 123 124 if (expectModuleTarget) { 125 // ModuleTarget attribute is retained 126 if (! hasModuleTarget(md.name())) { 127 throw new RuntimeException("ModuleTarget missing for " + md.name()); 128 } 129 } else { 130 // by default ModuleTarget attribute is dropped 131 if (hasModuleTarget(md.name())) { 132 throw new RuntimeException("ModuleTarget present for " + md.name()); 133 } 134 } 135 136 Set<String> pkgs = md.packages(); 137 if (!pkgs.equals(Set.of(packages))) { 138 throw new RuntimeException(pkgs + " expected: " + Set.of(packages)); 139 } 140 } 141} 142