mchung@1638: /* mchung@2538: * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. mchung@1638: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mchung@1638: * mchung@1638: * This code is free software; you can redistribute it and/or modify it mchung@1638: * under the terms of the GNU General Public License version 2 only, as mchung@1638: * published by the Free Software Foundation. Oracle designates this mchung@1638: * particular file as subject to the "Classpath" exception as provided mchung@1638: * by Oracle in the LICENSE file that accompanied this code. mchung@1638: * mchung@1638: * This code is distributed in the hope that it will be useful, but WITHOUT mchung@1638: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mchung@1638: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mchung@1638: * version 2 for more details (a copy is included in the LICENSE file that mchung@1638: * accompanied this code). mchung@1638: * mchung@1638: * You should have received a copy of the GNU General Public License version mchung@1638: * 2 along with this work; if not, write to the Free Software Foundation, mchung@1638: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mchung@1638: * mchung@1638: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mchung@1638: * or visit www.oracle.com if you need additional information or have any mchung@1638: * questions. mchung@1638: */ mchung@1638: package com.sun.tools.jdeps; mchung@1638: mchung@1638: import com.sun.tools.classfile.Annotation; mchung@1638: import com.sun.tools.classfile.Annotation.*; mchung@1638: import com.sun.tools.classfile.Attribute; mchung@1638: import com.sun.tools.classfile.ClassFile; mchung@1638: import com.sun.tools.classfile.ConstantPool.*; mchung@1638: import com.sun.tools.classfile.ConstantPoolException; mchung@1638: import com.sun.tools.classfile.RuntimeAnnotations_attribute; mchung@1638: import java.io.FileReader; mchung@1638: import java.io.IOException; mchung@2139: import java.nio.file.Files; mchung@1638: import java.nio.file.Path; mchung@1638: import java.nio.file.Paths; mchung@1638: import java.util.*; mchung@1638: import java.util.jar.JarFile; mchung@1638: mchung@1638: /** mchung@1638: * Build the profile information from ct.sym if exists. mchung@1638: */ mchung@2139: enum Profile { mchung@2139: COMPACT1("compact1", 1), mchung@2139: COMPACT2("compact2", 2), mchung@2139: COMPACT3("compact3", 3), mchung@2139: FULL_JRE("Full JRE", 4); mchung@2139: mchung@2139: final String name; mchung@2139: final int profile; mchung@2139: final Set packages; mchung@2139: final Set proprietaryPkgs; mchung@2139: mchung@2139: Profile(String name, int profile) { mchung@2139: this.name = name; mchung@2139: this.profile = profile; mchung@2139: this.packages = new HashSet<>(); mchung@2139: this.proprietaryPkgs = new HashSet<>(); mchung@2139: } mchung@2139: mchung@2538: public String profileName() { mchung@2139: return name; mchung@1638: } mchung@1638: mchung@1638: public static int getProfileCount() { mchung@2139: return PackageToProfile.map.values().size(); mchung@1638: } mchung@1638: mchung@2139: /** mchung@2139: * Returns the Profile for the given package name. It returns an empty mchung@2139: * string if the given package is not in any profile. mchung@2139: */ mchung@2139: public static Profile getProfile(String pn) { mchung@2139: Profile profile = PackageToProfile.map.get(pn); mchung@2139: return (profile != null && profile.packages.contains(pn)) mchung@2538: ? profile : null; mchung@2139: } mchung@2139: mchung@2139: static class PackageToProfile { mchung@2172: static String[] JAVAX_CRYPTO_PKGS = new String[] { mchung@2172: "javax.crypto", mchung@2172: "javax.crypto.interfaces", mchung@2172: "javax.crypto.spec" mchung@2172: }; mchung@2139: static Map map = initProfiles(); mchung@2139: private static Map initProfiles() { mchung@2139: try { mchung@2139: String profilesProps = System.getProperty("jdeps.profiles"); mchung@2139: if (profilesProps != null) { mchung@2139: // for testing for JDK development build where ct.sym doesn't exist mchung@2139: initProfilesFromProperties(profilesProps); mchung@2139: } else { mchung@2139: Path home = Paths.get(System.getProperty("java.home")); mchung@2139: if (home.endsWith("jre")) { mchung@2139: home = home.getParent(); mchung@2139: } mchung@2139: Path ctsym = home.resolve("lib").resolve("ct.sym"); mchung@2139: if (Files.exists(ctsym)) { mchung@2139: // parse ct.sym and load information about profiles mchung@2139: try (JarFile jf = new JarFile(ctsym.toFile())) { mchung@2139: ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf); mchung@2139: for (ClassFile cf : reader.getClassFiles()) { mchung@2139: findProfile(cf); mchung@2139: } mchung@1638: } mchung@2172: // special case for javax.crypto.* classes that are not mchung@2172: // included in ct.sym since they are in jce.jar mchung@2172: Collections.addAll(Profile.COMPACT1.packages, JAVAX_CRYPTO_PKGS); mchung@1638: } mchung@2139: } mchung@2139: } catch (IOException | ConstantPoolException e) { mchung@2139: throw new Error(e); mchung@2139: } mchung@2139: HashMap map = new HashMap<>(); mchung@2139: for (Profile profile : Profile.values()) { mchung@2139: for (String pn : profile.packages) { mchung@2139: if (!map.containsKey(pn)) { mchung@2139: // split packages in the JRE: use the smaller compact mchung@2139: map.put(pn, profile); mchung@2139: } mchung@2139: } mchung@2139: for (String pn : profile.proprietaryPkgs) { mchung@2139: if (!map.containsKey(pn)) { mchung@2139: map.put(pn, profile); mchung@1638: } mchung@1638: } mchung@1638: } mchung@2139: return map; mchung@1638: } mchung@2139: private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; mchung@2139: private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;"; mchung@2139: private static Profile findProfile(ClassFile cf) throws ConstantPoolException { mchung@2139: RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) mchung@2139: cf.attributes.get(Attribute.RuntimeInvisibleAnnotations); mchung@2139: int index = 0; mchung@2139: boolean proprietary = false; mchung@2139: if (attr != null) { mchung@2139: for (int i = 0; i < attr.annotations.length; i++) { mchung@2139: Annotation ann = attr.annotations[i]; mchung@2139: String annType = cf.constant_pool.getUTF8Value(ann.type_index); mchung@2139: if (PROFILE_ANNOTATION.equals(annType)) { mchung@2139: for (int j = 0; j < ann.num_element_value_pairs; j++) { mchung@2139: Annotation.element_value_pair pair = ann.element_value_pairs[j]; mchung@2139: Primitive_element_value ev = (Primitive_element_value) pair.value; mchung@2139: CONSTANT_Integer_info info = (CONSTANT_Integer_info) mchung@2139: cf.constant_pool.get(ev.const_value_index); mchung@2139: index = info.value; mchung@2139: break; mchung@2139: } mchung@2139: } else if (PROPRIETARY_ANNOTATION.equals(annType)) { mchung@2139: proprietary = true; mchung@1638: } mchung@1638: } mchung@1638: } mchung@2139: mchung@2139: Profile p = null; // default mchung@2139: switch (index) { mchung@2139: case 1: mchung@2139: p = Profile.COMPACT1; break; mchung@2139: case 2: mchung@2139: p = Profile.COMPACT2; break; mchung@2139: case 3: mchung@2139: p = Profile.COMPACT3; break; mchung@2139: case 4: mchung@2139: p = Profile.FULL_JRE; break; mchung@2139: default: mchung@2139: // skip classes with profile=0 mchung@2139: // Inner classes are not annotated with the profile annotation mchung@2139: return null; mchung@2139: } mchung@2139: mchung@2139: String name = cf.getName(); mchung@2139: int i = name.lastIndexOf('/'); mchung@2139: name = (i > 0) ? name.substring(0, i).replace('/', '.') : ""; mchung@2139: if (proprietary) { mchung@2139: p.proprietaryPkgs.add(name); mchung@2139: } else { mchung@2139: p.packages.add(name); mchung@2139: } mchung@2139: return p; mchung@2139: } mchung@2139: mchung@2139: private static void initProfilesFromProperties(String path) throws IOException { mchung@2139: Properties props = new Properties(); mchung@2139: try (FileReader reader = new FileReader(path)) { mchung@2139: props.load(reader); mchung@2139: } mchung@2139: for (Profile prof : Profile.values()) { mchung@2139: int i = prof.profile; mchung@2139: String key = props.getProperty("profile." + i + ".name"); mchung@2139: if (key == null) { mchung@2139: throw new RuntimeException(key + " missing in " + path); mchung@2139: } mchung@2139: String n = props.getProperty("profile." + i + ".packages"); mchung@2139: String[] pkgs = n.split("\\s+"); mchung@2139: for (String p : pkgs) { mchung@2139: if (p.isEmpty()) continue; mchung@2139: prof.packages.add(p); mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: mchung@1638: // for debugging mchung@1638: public static void main(String[] args) { mchung@1638: if (args.length == 0) { mchung@2139: if (Profile.getProfileCount() == 0) { mchung@2139: System.err.println("No profile is present in this JDK"); mchung@1638: } mchung@2139: for (Profile p : Profile.values()) { mchung@1638: String profileName = p.name; mchung@2139: SortedSet set = new TreeSet<>(p.packages); mchung@1638: for (String s : set) { mchung@1638: // filter out the inner classes that are not annotated with mchung@1638: // the profile annotation mchung@2139: if (PackageToProfile.map.get(s) == p) { mchung@2139: System.out.format("%2d: %-10s %s%n", p.profile, profileName, s); mchung@1638: profileName = ""; mchung@2139: } else { mchung@2139: System.err.format("Split package: %s in %s and %s %n", mchung@2139: s, PackageToProfile.map.get(s).name, p.name); mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: for (String pn : args) { mchung@2139: System.out.format("%s in %s%n", pn, getProfile(pn)); mchung@1638: } mchung@1638: } mchung@1638: }