Sat, 07 Nov 2020 10:30:02 +0800
Added tag mips-jdk8u275-b01 for changeset eb6ee6a5f2fe
1 /*
2 * Copyright (c) 2012, 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 package com.sun.tools.jdeps;
27 import com.sun.tools.classfile.Annotation;
28 import com.sun.tools.classfile.ClassFile;
29 import com.sun.tools.classfile.ConstantPool;
30 import com.sun.tools.classfile.ConstantPoolException;
31 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
32 import com.sun.tools.classfile.Dependencies.ClassFileError;
33 import java.io.IOException;
34 import java.nio.file.FileVisitResult;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import java.nio.file.Paths;
38 import java.nio.file.SimpleFileVisitor;
39 import java.nio.file.attribute.BasicFileAttributes;
40 import java.util.*;
42 import static com.sun.tools.classfile.Attribute.*;
44 /**
45 * ClassPath for Java SE and JDK
46 */
47 class PlatformClassPath {
48 private static final List<String> NON_PLATFORM_JARFILES =
49 Arrays.asList("alt-rt.jar", "ant-javafx.jar", "javafx-mx.jar");
50 private static final List<Archive> javaHomeArchives = init();
52 static List<Archive> getArchives() {
53 return javaHomeArchives;
54 }
56 private static List<Archive> init() {
57 List<Archive> result = new ArrayList<>();
58 Path home = Paths.get(System.getProperty("java.home"));
59 try {
60 if (home.endsWith("jre")) {
61 // jar files in <javahome>/jre/lib
62 result.addAll(addJarFiles(home.resolve("lib")));
63 if (home.getParent() != null) {
64 // add tools.jar and other JDK jar files
65 Path lib = home.getParent().resolve("lib");
66 if (Files.exists(lib)) {
67 result.addAll(addJarFiles(lib));
68 }
69 }
70 } else if (Files.exists(home.resolve("lib"))) {
71 // either a JRE or a jdk build image
72 Path classes = home.resolve("classes");
73 if (Files.isDirectory(classes)) {
74 // jdk build outputdir
75 result.add(new JDKArchive(classes));
76 }
77 // add other JAR files
78 result.addAll(addJarFiles(home.resolve("lib")));
79 } else {
80 throw new RuntimeException("\"" + home + "\" not a JDK home");
81 }
82 return result;
83 } catch (IOException e) {
84 throw new Error(e);
85 }
86 }
88 private static List<Archive> addJarFiles(final Path root) throws IOException {
89 final List<Archive> result = new ArrayList<>();
90 final Path ext = root.resolve("ext");
91 Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
92 @Override
93 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
94 throws IOException
95 {
96 if (dir.equals(root) || dir.equals(ext)) {
97 return FileVisitResult.CONTINUE;
98 } else {
99 // skip other cobundled JAR files
100 return FileVisitResult.SKIP_SUBTREE;
101 }
102 }
103 @Override
104 public FileVisitResult visitFile(Path p, BasicFileAttributes attrs)
105 throws IOException
106 {
107 String fn = p.getFileName().toString();
108 if (fn.endsWith(".jar")) {
109 // JDK may cobundle with JavaFX that doesn't belong to any profile
110 // Treat jfxrt.jar as regular Archive
111 result.add(NON_PLATFORM_JARFILES.contains(fn)
112 ? Archive.getInstance(p)
113 : new JDKArchive(p));
114 }
115 return FileVisitResult.CONTINUE;
116 }
117 });
118 return result;
119 }
121 /**
122 * A JDK archive is part of the JDK containing the Java SE API
123 * or implementation classes (i.e. JDK internal API)
124 */
125 static class JDKArchive extends Archive {
126 private static List<String> PROFILE_JARS = Arrays.asList("rt.jar", "jce.jar");
127 // Workaround: The following packages are not annotated as jdk.Exported
128 private static List<String> EXPORTED_PACKAGES = Arrays.asList(
129 "javax.jnlp",
130 "org.w3c.dom.css",
131 "org.w3c.dom.html",
132 "org.w3c.dom.stylesheets",
133 "org.w3c.dom.xpath"
134 );
135 public static boolean isProfileArchive(Archive archive) {
136 if (archive instanceof JDKArchive) {
137 return PROFILE_JARS.contains(archive.getName());
138 }
139 return false;
140 }
142 private final Map<String,Boolean> exportedPackages = new HashMap<>();
143 private final Map<String,Boolean> exportedTypes = new HashMap<>();
144 JDKArchive(Path p) throws IOException {
145 super(p, ClassFileReader.newInstance(p));
146 }
148 /**
149 * Tests if a given fully-qualified name is an exported type.
150 */
151 public boolean isExported(String cn) {
152 int i = cn.lastIndexOf('.');
153 String pn = i > 0 ? cn.substring(0, i) : "";
155 boolean isJdkExported = isExportedPackage(pn);
156 if (exportedTypes.containsKey(cn)) {
157 return exportedTypes.get(cn);
158 }
159 return isJdkExported;
160 }
162 /**
163 * Tests if a given package name is exported.
164 */
165 public boolean isExportedPackage(String pn) {
166 if (Profile.getProfile(pn) != null) {
167 return true;
168 }
169 // special case for JavaFX and APIs that are not annotated with @jdk.Exported)
170 if (EXPORTED_PACKAGES.contains(pn) || pn.startsWith("javafx.")) {
171 return true;
172 }
173 return exportedPackages.containsKey(pn) ? exportedPackages.get(pn) : false;
174 }
176 private static final String JDK_EXPORTED_ANNOTATION = "Ljdk/Exported;";
177 private Boolean isJdkExported(ClassFile cf) throws ConstantPoolException {
178 RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute)
179 cf.attributes.get(RuntimeVisibleAnnotations);
180 if (attr != null) {
181 for (int i = 0; i < attr.annotations.length; i++) {
182 Annotation ann = attr.annotations[i];
183 String annType = cf.constant_pool.getUTF8Value(ann.type_index);
184 if (JDK_EXPORTED_ANNOTATION.equals(annType)) {
185 boolean isJdkExported = true;
186 for (int j = 0; j < ann.num_element_value_pairs; j++) {
187 Annotation.element_value_pair pair = ann.element_value_pairs[j];
188 Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) pair.value;
189 ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info)
190 cf.constant_pool.get(ev.const_value_index);
191 isJdkExported = info.value != 0;
192 }
193 return Boolean.valueOf(isJdkExported);
194 }
195 }
196 }
197 return null;
198 }
200 void processJdkExported(ClassFile cf) throws IOException {
201 try {
202 String cn = cf.getName();
203 String pn = cn.substring(0, cn.lastIndexOf('/')).replace('/', '.');
205 Boolean b = isJdkExported(cf);
206 if (b != null) {
207 exportedTypes.put(cn.replace('/', '.'), b);
208 }
209 if (!exportedPackages.containsKey(pn)) {
210 // check if package-info.class has @jdk.Exported
211 Boolean isJdkExported = null;
212 ClassFile pcf = reader().getClassFile(cn.substring(0, cn.lastIndexOf('/')+1) + "package-info");
213 if (pcf != null) {
214 isJdkExported = isJdkExported(pcf);
215 }
216 if (isJdkExported != null) {
217 exportedPackages.put(pn, isJdkExported);
218 }
219 }
220 } catch (ConstantPoolException e) {
221 throw new ClassFileError(e);
222 }
223 }
224 }
225 }