Thu, 12 Oct 2017 19:50:01 +0800
merge
aoqi@0 | 1 | /* |
mchung@2538 | 2 | * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. Oracle designates this |
aoqi@0 | 8 | * particular file as subject to the "Classpath" exception as provided |
aoqi@0 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
aoqi@0 | 10 | * |
aoqi@0 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 15 | * accompanied this code). |
aoqi@0 | 16 | * |
aoqi@0 | 17 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 20 | * |
aoqi@0 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 22 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 23 | * questions. |
aoqi@0 | 24 | */ |
aoqi@0 | 25 | package com.sun.tools.jdeps; |
aoqi@0 | 26 | |
mchung@2538 | 27 | import com.sun.tools.classfile.Annotation; |
mchung@2538 | 28 | import com.sun.tools.classfile.ClassFile; |
mchung@2538 | 29 | import com.sun.tools.classfile.ConstantPool; |
mchung@2538 | 30 | import com.sun.tools.classfile.ConstantPoolException; |
mchung@2538 | 31 | import com.sun.tools.classfile.RuntimeAnnotations_attribute; |
mchung@2538 | 32 | import com.sun.tools.classfile.Dependencies.ClassFileError; |
aoqi@0 | 33 | import java.io.IOException; |
aoqi@0 | 34 | import java.nio.file.FileVisitResult; |
aoqi@0 | 35 | import java.nio.file.Files; |
aoqi@0 | 36 | import java.nio.file.Path; |
aoqi@0 | 37 | import java.nio.file.Paths; |
aoqi@0 | 38 | import java.nio.file.SimpleFileVisitor; |
aoqi@0 | 39 | import java.nio.file.attribute.BasicFileAttributes; |
aoqi@0 | 40 | import java.util.*; |
aoqi@0 | 41 | |
mchung@2538 | 42 | import static com.sun.tools.classfile.Attribute.*; |
mchung@2538 | 43 | |
aoqi@0 | 44 | /** |
aoqi@0 | 45 | * ClassPath for Java SE and JDK |
aoqi@0 | 46 | */ |
aoqi@0 | 47 | class PlatformClassPath { |
mchung@2538 | 48 | private static final List<String> NON_PLATFORM_JARFILES = |
mchung@2538 | 49 | Arrays.asList("alt-rt.jar", "jfxrt.jar", "ant-javafx.jar", "javafx-mx.jar"); |
mchung@2538 | 50 | private static final List<Archive> javaHomeArchives = init(); |
aoqi@0 | 51 | |
aoqi@0 | 52 | static List<Archive> getArchives() { |
aoqi@0 | 53 | return javaHomeArchives; |
aoqi@0 | 54 | } |
aoqi@0 | 55 | |
aoqi@0 | 56 | private static List<Archive> init() { |
aoqi@0 | 57 | List<Archive> result = new ArrayList<>(); |
aoqi@0 | 58 | Path home = Paths.get(System.getProperty("java.home")); |
aoqi@0 | 59 | try { |
aoqi@0 | 60 | if (home.endsWith("jre")) { |
aoqi@0 | 61 | // jar files in <javahome>/jre/lib |
aoqi@0 | 62 | result.addAll(addJarFiles(home.resolve("lib"))); |
mchung@2538 | 63 | if (home.getParent() != null) { |
mchung@2538 | 64 | // add tools.jar and other JDK jar files |
mchung@2538 | 65 | Path lib = home.getParent().resolve("lib"); |
mchung@2538 | 66 | if (Files.exists(lib)) { |
mchung@2538 | 67 | result.addAll(addJarFiles(lib)); |
mchung@2538 | 68 | } |
mchung@2538 | 69 | } |
aoqi@0 | 70 | } else if (Files.exists(home.resolve("lib"))) { |
aoqi@0 | 71 | // either a JRE or a jdk build image |
aoqi@0 | 72 | Path classes = home.resolve("classes"); |
aoqi@0 | 73 | if (Files.isDirectory(classes)) { |
aoqi@0 | 74 | // jdk build outputdir |
mchung@2538 | 75 | result.add(new JDKArchive(classes)); |
aoqi@0 | 76 | } |
aoqi@0 | 77 | // add other JAR files |
aoqi@0 | 78 | result.addAll(addJarFiles(home.resolve("lib"))); |
aoqi@0 | 79 | } else { |
aoqi@0 | 80 | throw new RuntimeException("\"" + home + "\" not a JDK home"); |
aoqi@0 | 81 | } |
aoqi@0 | 82 | return result; |
aoqi@0 | 83 | } catch (IOException e) { |
aoqi@0 | 84 | throw new Error(e); |
aoqi@0 | 85 | } |
aoqi@0 | 86 | } |
aoqi@0 | 87 | |
aoqi@0 | 88 | private static List<Archive> addJarFiles(final Path root) throws IOException { |
aoqi@0 | 89 | final List<Archive> result = new ArrayList<>(); |
aoqi@0 | 90 | final Path ext = root.resolve("ext"); |
aoqi@0 | 91 | Files.walkFileTree(root, new SimpleFileVisitor<Path>() { |
aoqi@0 | 92 | @Override |
aoqi@0 | 93 | public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) |
aoqi@0 | 94 | throws IOException |
aoqi@0 | 95 | { |
aoqi@0 | 96 | if (dir.equals(root) || dir.equals(ext)) { |
aoqi@0 | 97 | return FileVisitResult.CONTINUE; |
aoqi@0 | 98 | } else { |
aoqi@0 | 99 | // skip other cobundled JAR files |
aoqi@0 | 100 | return FileVisitResult.SKIP_SUBTREE; |
aoqi@0 | 101 | } |
aoqi@0 | 102 | } |
aoqi@0 | 103 | @Override |
aoqi@0 | 104 | public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) |
aoqi@0 | 105 | throws IOException |
aoqi@0 | 106 | { |
aoqi@0 | 107 | String fn = p.getFileName().toString(); |
aoqi@0 | 108 | if (fn.endsWith(".jar")) { |
aoqi@0 | 109 | // JDK may cobundle with JavaFX that doesn't belong to any profile |
aoqi@0 | 110 | // Treat jfxrt.jar as regular Archive |
mchung@2538 | 111 | result.add(NON_PLATFORM_JARFILES.contains(fn) |
mchung@2538 | 112 | ? Archive.getInstance(p) |
mchung@2538 | 113 | : new JDKArchive(p)); |
aoqi@0 | 114 | } |
aoqi@0 | 115 | return FileVisitResult.CONTINUE; |
aoqi@0 | 116 | } |
aoqi@0 | 117 | }); |
aoqi@0 | 118 | return result; |
aoqi@0 | 119 | } |
aoqi@0 | 120 | |
aoqi@0 | 121 | /** |
aoqi@0 | 122 | * A JDK archive is part of the JDK containing the Java SE API |
aoqi@0 | 123 | * or implementation classes (i.e. JDK internal API) |
aoqi@0 | 124 | */ |
aoqi@0 | 125 | static class JDKArchive extends Archive { |
mchung@2538 | 126 | private static List<String> PROFILE_JARS = Arrays.asList("rt.jar", "jce.jar"); |
mchung@2538 | 127 | public static boolean isProfileArchive(Archive archive) { |
mchung@2538 | 128 | if (archive instanceof JDKArchive) { |
mchung@2538 | 129 | return PROFILE_JARS.contains(archive.getName()); |
mchung@2538 | 130 | } |
mchung@2538 | 131 | return false; |
mchung@2538 | 132 | } |
mchung@2538 | 133 | |
mchung@2538 | 134 | private final Map<String,Boolean> exportedPackages = new HashMap<>(); |
mchung@2538 | 135 | private final Map<String,Boolean> exportedTypes = new HashMap<>(); |
mchung@2538 | 136 | JDKArchive(Path p) throws IOException { |
mchung@2538 | 137 | super(p, ClassFileReader.newInstance(p)); |
mchung@2538 | 138 | } |
mchung@2538 | 139 | |
mchung@2538 | 140 | /** |
mchung@2538 | 141 | * Tests if a given fully-qualified name is an exported type. |
mchung@2538 | 142 | */ |
mchung@2538 | 143 | public boolean isExported(String cn) { |
mchung@2538 | 144 | int i = cn.lastIndexOf('.'); |
mchung@2538 | 145 | String pn = i > 0 ? cn.substring(0, i) : ""; |
mchung@2538 | 146 | |
mchung@2538 | 147 | boolean isJdkExported = isExportedPackage(pn); |
mchung@2538 | 148 | if (exportedTypes.containsKey(cn)) { |
mchung@2538 | 149 | return exportedTypes.get(cn); |
mchung@2538 | 150 | } |
mchung@2538 | 151 | return isJdkExported; |
mchung@2538 | 152 | } |
mchung@2538 | 153 | |
mchung@2538 | 154 | /** |
mchung@2538 | 155 | * Tests if a given package name is exported. |
mchung@2538 | 156 | */ |
mchung@2538 | 157 | public boolean isExportedPackage(String pn) { |
mchung@2626 | 158 | if (Profile.getProfile(pn) != null || "javax.jnlp".equals(pn)) { |
mchung@2538 | 159 | return true; |
mchung@2538 | 160 | } |
mchung@2538 | 161 | return exportedPackages.containsKey(pn) ? exportedPackages.get(pn) : false; |
mchung@2538 | 162 | } |
mchung@2538 | 163 | |
mchung@2538 | 164 | private static final String JDK_EXPORTED_ANNOTATION = "Ljdk/Exported;"; |
mchung@2538 | 165 | private Boolean isJdkExported(ClassFile cf) throws ConstantPoolException { |
mchung@2538 | 166 | RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) |
mchung@2538 | 167 | cf.attributes.get(RuntimeVisibleAnnotations); |
mchung@2538 | 168 | if (attr != null) { |
mchung@2538 | 169 | for (int i = 0; i < attr.annotations.length; i++) { |
mchung@2538 | 170 | Annotation ann = attr.annotations[i]; |
mchung@2538 | 171 | String annType = cf.constant_pool.getUTF8Value(ann.type_index); |
mchung@2538 | 172 | if (JDK_EXPORTED_ANNOTATION.equals(annType)) { |
mchung@2538 | 173 | boolean isJdkExported = true; |
mchung@2538 | 174 | for (int j = 0; j < ann.num_element_value_pairs; j++) { |
mchung@2538 | 175 | Annotation.element_value_pair pair = ann.element_value_pairs[j]; |
mchung@2538 | 176 | Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) pair.value; |
mchung@2538 | 177 | ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info) |
mchung@2538 | 178 | cf.constant_pool.get(ev.const_value_index); |
mchung@2538 | 179 | isJdkExported = info.value != 0; |
mchung@2538 | 180 | } |
mchung@2538 | 181 | return Boolean.valueOf(isJdkExported); |
mchung@2538 | 182 | } |
mchung@2538 | 183 | } |
mchung@2538 | 184 | } |
mchung@2538 | 185 | return null; |
mchung@2538 | 186 | } |
mchung@2538 | 187 | |
mchung@2538 | 188 | void processJdkExported(ClassFile cf) throws IOException { |
mchung@2538 | 189 | try { |
mchung@2538 | 190 | String cn = cf.getName(); |
mchung@2538 | 191 | String pn = cn.substring(0, cn.lastIndexOf('/')).replace('/', '.'); |
mchung@2538 | 192 | |
mchung@2538 | 193 | Boolean b = isJdkExported(cf); |
mchung@2538 | 194 | if (b != null) { |
mchung@2538 | 195 | exportedTypes.put(cn.replace('/', '.'), b); |
mchung@2538 | 196 | } |
mchung@2538 | 197 | if (!exportedPackages.containsKey(pn)) { |
mchung@2538 | 198 | // check if package-info.class has @jdk.Exported |
mchung@2538 | 199 | Boolean isJdkExported = null; |
mchung@2538 | 200 | ClassFile pcf = reader().getClassFile(cn.substring(0, cn.lastIndexOf('/')+1) + "package-info"); |
mchung@2538 | 201 | if (pcf != null) { |
mchung@2538 | 202 | isJdkExported = isJdkExported(pcf); |
mchung@2538 | 203 | } |
mchung@2538 | 204 | if (isJdkExported != null) { |
mchung@2538 | 205 | exportedPackages.put(pn, isJdkExported); |
mchung@2538 | 206 | } |
mchung@2538 | 207 | } |
mchung@2538 | 208 | } catch (ConstantPoolException e) { |
mchung@2538 | 209 | throw new ClassFileError(e); |
mchung@2538 | 210 | } |
aoqi@0 | 211 | } |
aoqi@0 | 212 | } |
aoqi@0 | 213 | } |