mchung@1638: /* mchung@1638: * Copyright (c) 2013, 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.ConstantPool.*; mchung@1638: import com.sun.tools.classfile.ConstantPoolException; mchung@1638: import com.sun.tools.classfile.RuntimeAnnotations_attribute; mchung@1638: import java.io.File; mchung@1638: import java.io.FileReader; mchung@1638: import java.io.IOException; 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@1638: class Profiles { mchung@1638: private static final Map map = initProfiles(); mchung@1638: /** mchung@1638: * Returns the name of the profile for the given package name. mchung@1638: * It returns an empty string if the given package is not in any profile. mchung@1638: */ mchung@1638: public static String getProfileName(String pn) { mchung@1638: Profile profile = map.get(pn); mchung@1638: return (profile != null && profile.packages.contains(pn)) mchung@1638: ? profile.name : ""; mchung@1638: } mchung@1638: mchung@1638: public static int getProfileCount() { mchung@1638: return new HashSet(map.values()).size(); mchung@1638: } mchung@1638: mchung@1638: private static Map initProfiles() { mchung@1638: List profiles = new ArrayList(); mchung@1638: try { mchung@1638: String profilesProps = System.getProperty("jdeps.profiles"); mchung@1638: if (profilesProps != null) { mchung@1638: // for testing for JDK development build where ct.sym doesn't exist mchung@1638: initProfilesFromProperties(profiles, profilesProps); mchung@1638: } else { mchung@1638: Path home = Paths.get(System.getProperty("java.home")); mchung@1638: if (home.endsWith("jre")) { mchung@1638: home = home.getParent(); mchung@1638: } mchung@1638: Path ctsym = home.resolve("lib").resolve("ct.sym"); mchung@1638: if (ctsym.toFile().exists()) { mchung@1638: // add a default Full JRE mchung@1638: profiles.add(0, new Profile("Full JRE", 0)); mchung@1638: // parse ct.sym and load information about profiles mchung@1638: try (JarFile jf = new JarFile(ctsym.toFile())) { mchung@1638: ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf); mchung@1638: for (ClassFile cf : reader.getClassFiles()) { mchung@1638: findProfile(profiles, cf); mchung@1638: } mchung@1638: } mchung@1638: mchung@1638: // merge the last Profile with the "Full JRE" mchung@1638: if (profiles.size() > 1) { mchung@1638: Profile fullJRE = profiles.get(0); mchung@1638: Profile p = profiles.remove(profiles.size() - 1); mchung@1638: for (String pn : fullJRE.packages) { mchung@1638: // The last profile contains the packages determined from ct.sym. mchung@1638: // Move classes annotated profile==0 or no attribute that are mchung@1638: // added in the fullJRE profile to either supported or proprietary mchung@1638: // packages appropriately mchung@1638: if (p.proprietaryPkgs.contains(pn)) { mchung@1638: p.proprietaryPkgs.add(pn); mchung@1638: } else { mchung@1638: p.packages.add(pn); mchung@1638: } mchung@1638: } mchung@1638: fullJRE.packages.clear(); mchung@1638: fullJRE.proprietaryPkgs.clear(); mchung@1638: fullJRE.packages.addAll(p.packages); mchung@1638: fullJRE.proprietaryPkgs.addAll(p.proprietaryPkgs); mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: } catch (IOException | ConstantPoolException e) { mchung@1638: throw new Error(e); mchung@1638: } mchung@1638: HashMap map = new HashMap(); mchung@1638: for (Profile profile : profiles) { mchung@1638: // Inner classes are not annotated with the profile annotation mchung@1638: // packages may be in one profile but also appear in the Full JRE mchung@1638: // Full JRE is always the first element in profiles list and mchung@1638: // so the map will contain the appropriate Profile mchung@1638: for (String pn : profile.packages) { mchung@1638: map.put(pn, profile); mchung@1638: } mchung@1638: for (String pn : profile.proprietaryPkgs) { mchung@1638: map.put(pn, profile); mchung@1638: } mchung@1638: } mchung@1638: return map; mchung@1638: } mchung@1638: mchung@1638: private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; mchung@1638: private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;"; mchung@1638: private static Profile findProfile(List profiles, ClassFile cf) mchung@1638: throws ConstantPoolException mchung@1638: { mchung@1638: RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) mchung@1638: cf.attributes.get(Attribute.RuntimeInvisibleAnnotations); mchung@1638: int index = 0; mchung@1638: boolean proprietary = false; mchung@1638: if (attr != null) { mchung@1638: for (int i = 0; i < attr.annotations.length; i++) { mchung@1638: Annotation ann = attr.annotations[i]; mchung@1638: String annType = cf.constant_pool.getUTF8Value(ann.type_index); mchung@1638: if (PROFILE_ANNOTATION.equals(annType)) { mchung@1638: for (int j = 0; j < ann.num_element_value_pairs; j++) { mchung@1638: Annotation.element_value_pair pair = ann.element_value_pairs[j]; mchung@1638: Primitive_element_value ev = (Primitive_element_value)pair.value; mchung@1638: CONSTANT_Integer_info info = (CONSTANT_Integer_info) mchung@1638: cf.constant_pool.get(ev.const_value_index); mchung@1638: index = info.value; mchung@1638: break; mchung@1638: } mchung@1638: } else if (PROPRIETARY_ANNOTATION.equals(annType)) { mchung@1638: proprietary = true; mchung@1638: } mchung@1638: } mchung@1638: if (index >= profiles.size()) { mchung@1638: Profile p = null; mchung@1638: for (int i = profiles.size(); i <= index; i++) { mchung@1638: p = new Profile(i); mchung@1638: profiles.add(p); mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: mchung@1638: Profile p = profiles.get(index); mchung@1638: String name = cf.getName(); mchung@1638: int i = name.lastIndexOf('/'); mchung@1638: name = (i > 0) ? name.substring(0, i).replace('/','.') : ""; mchung@1638: if (proprietary) { mchung@1638: p.proprietaryPkgs.add(name); mchung@1638: } else { mchung@1638: p.packages.add(name); mchung@1638: } mchung@1638: return p; mchung@1638: } mchung@1638: mchung@1638: private static void initProfilesFromProperties(List profiles, String path) mchung@1638: throws IOException mchung@1638: { mchung@1638: Properties props = new Properties(); mchung@1638: try (FileReader reader = new FileReader(path)) { mchung@1638: props.load(reader); mchung@1638: } mchung@1638: int i=1; mchung@1638: String key; mchung@1638: while (props.containsKey((key = "profile." + i + ".name"))) { mchung@1638: Profile profile = new Profile(props.getProperty(key), i); mchung@1638: profiles.add(profile); mchung@1638: String n = props.getProperty("profile." + i + ".packages"); mchung@1638: String[] pkgs = n.split("\\s+"); mchung@1638: for (String p : pkgs) { mchung@1638: if (p.isEmpty()) continue; mchung@1638: profile.packages.add(p); mchung@1638: } mchung@1638: i++; mchung@1638: } mchung@1638: } mchung@1638: mchung@1638: private static class Profile { mchung@1638: final String name; mchung@1638: final int profile; mchung@1638: final Set packages; mchung@1638: final Set proprietaryPkgs; mchung@1638: Profile(int profile) { mchung@1638: this("compact" + profile, profile); mchung@1638: } mchung@1638: Profile(String name, int profile) { mchung@1638: this.name = name; mchung@1638: this.profile = profile; mchung@1638: this.packages = new HashSet(); mchung@1638: this.proprietaryPkgs = new HashSet(); mchung@1638: } mchung@1638: public String toString() { mchung@1638: return name; 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@1638: Profile[] profiles = new Profile[getProfileCount()]; mchung@1638: for (Profile p : map.values()) { mchung@1638: // move the zeroth profile to the last mchung@1638: int index = p.profile == 0 ? profiles.length-1 : p.profile-1; mchung@1638: profiles[index] = p; mchung@1638: } mchung@1638: for (Profile p : profiles) { mchung@1638: String profileName = p.name; mchung@1638: 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@1638: if (map.get(s) == p) { mchung@1638: System.out.format("%-10s %s%n", profileName, s); mchung@1638: profileName = ""; mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: } mchung@1638: for (String pn : args) { mchung@1638: System.out.format("%s in %s%n", pn, getProfileName(pn)); mchung@1638: } mchung@1638: } mchung@1638: }