1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/jdeps/Profile.java Thu Oct 17 13:19:48 2013 -0700 1.3 @@ -0,0 +1,227 @@ 1.4 +/* 1.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 +package com.sun.tools.jdeps; 1.29 + 1.30 +import com.sun.tools.classfile.Annotation; 1.31 +import com.sun.tools.classfile.Annotation.*; 1.32 +import com.sun.tools.classfile.Attribute; 1.33 +import com.sun.tools.classfile.ClassFile; 1.34 +import com.sun.tools.classfile.ConstantPool.*; 1.35 +import com.sun.tools.classfile.ConstantPoolException; 1.36 +import com.sun.tools.classfile.RuntimeAnnotations_attribute; 1.37 +import java.io.FileReader; 1.38 +import java.io.IOException; 1.39 +import java.nio.file.Files; 1.40 +import java.nio.file.Path; 1.41 +import java.nio.file.Paths; 1.42 +import java.util.*; 1.43 +import java.util.jar.JarFile; 1.44 + 1.45 +/** 1.46 + * Build the profile information from ct.sym if exists. 1.47 + */ 1.48 +enum Profile { 1.49 + 1.50 + COMPACT1("compact1", 1), 1.51 + COMPACT2("compact2", 2), 1.52 + COMPACT3("compact3", 3), 1.53 + FULL_JRE("Full JRE", 4); 1.54 + 1.55 + final String name; 1.56 + final int profile; 1.57 + final Set<String> packages; 1.58 + final Set<String> proprietaryPkgs; 1.59 + 1.60 + Profile(String name, int profile) { 1.61 + this.name = name; 1.62 + this.profile = profile; 1.63 + this.packages = new HashSet<>(); 1.64 + this.proprietaryPkgs = new HashSet<>(); 1.65 + } 1.66 + 1.67 + @Override 1.68 + public String toString() { 1.69 + return name; 1.70 + } 1.71 + 1.72 + public static int getProfileCount() { 1.73 + return PackageToProfile.map.values().size(); 1.74 + } 1.75 + 1.76 + /** 1.77 + * Returns the Profile for the given package name. It returns an empty 1.78 + * string if the given package is not in any profile. 1.79 + */ 1.80 + public static Profile getProfile(String pn) { 1.81 + Profile profile = PackageToProfile.map.get(pn); 1.82 + return (profile != null && profile.packages.contains(pn)) 1.83 + ? profile : null; 1.84 + } 1.85 + 1.86 + static class PackageToProfile { 1.87 + static Map<String, Profile> map = initProfiles(); 1.88 + 1.89 + private static Map<String, Profile> initProfiles() { 1.90 + try { 1.91 + String profilesProps = System.getProperty("jdeps.profiles"); 1.92 + if (profilesProps != null) { 1.93 + // for testing for JDK development build where ct.sym doesn't exist 1.94 + initProfilesFromProperties(profilesProps); 1.95 + } else { 1.96 + Path home = Paths.get(System.getProperty("java.home")); 1.97 + if (home.endsWith("jre")) { 1.98 + home = home.getParent(); 1.99 + } 1.100 + Path ctsym = home.resolve("lib").resolve("ct.sym"); 1.101 + if (Files.exists(ctsym)) { 1.102 + // parse ct.sym and load information about profiles 1.103 + try (JarFile jf = new JarFile(ctsym.toFile())) { 1.104 + ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf); 1.105 + for (ClassFile cf : reader.getClassFiles()) { 1.106 + findProfile(cf); 1.107 + } 1.108 + } 1.109 + } 1.110 + } 1.111 + } catch (IOException | ConstantPoolException e) { 1.112 + throw new Error(e); 1.113 + } 1.114 + HashMap<String,Profile> map = new HashMap<>(); 1.115 + for (Profile profile : Profile.values()) { 1.116 + for (String pn : profile.packages) { 1.117 + if (!map.containsKey(pn)) { 1.118 + // split packages in the JRE: use the smaller compact 1.119 + map.put(pn, profile); 1.120 + } 1.121 + } 1.122 + for (String pn : profile.proprietaryPkgs) { 1.123 + if (!map.containsKey(pn)) { 1.124 + map.put(pn, profile); 1.125 + } 1.126 + } 1.127 + } 1.128 + return map; 1.129 + } 1.130 + private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; 1.131 + private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;"; 1.132 + private static Profile findProfile(ClassFile cf) throws ConstantPoolException { 1.133 + RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) 1.134 + cf.attributes.get(Attribute.RuntimeInvisibleAnnotations); 1.135 + int index = 0; 1.136 + boolean proprietary = false; 1.137 + if (attr != null) { 1.138 + for (int i = 0; i < attr.annotations.length; i++) { 1.139 + Annotation ann = attr.annotations[i]; 1.140 + String annType = cf.constant_pool.getUTF8Value(ann.type_index); 1.141 + if (PROFILE_ANNOTATION.equals(annType)) { 1.142 + for (int j = 0; j < ann.num_element_value_pairs; j++) { 1.143 + Annotation.element_value_pair pair = ann.element_value_pairs[j]; 1.144 + Primitive_element_value ev = (Primitive_element_value) pair.value; 1.145 + CONSTANT_Integer_info info = (CONSTANT_Integer_info) 1.146 + cf.constant_pool.get(ev.const_value_index); 1.147 + index = info.value; 1.148 + break; 1.149 + } 1.150 + } else if (PROPRIETARY_ANNOTATION.equals(annType)) { 1.151 + proprietary = true; 1.152 + } 1.153 + } 1.154 + } 1.155 + 1.156 + Profile p = null; // default 1.157 + switch (index) { 1.158 + case 1: 1.159 + p = Profile.COMPACT1; break; 1.160 + case 2: 1.161 + p = Profile.COMPACT2; break; 1.162 + case 3: 1.163 + p = Profile.COMPACT3; break; 1.164 + case 4: 1.165 + p = Profile.FULL_JRE; break; 1.166 + default: 1.167 + // skip classes with profile=0 1.168 + // Inner classes are not annotated with the profile annotation 1.169 + return null; 1.170 + } 1.171 + 1.172 + String name = cf.getName(); 1.173 + int i = name.lastIndexOf('/'); 1.174 + name = (i > 0) ? name.substring(0, i).replace('/', '.') : ""; 1.175 + if (proprietary) { 1.176 + p.proprietaryPkgs.add(name); 1.177 + } else { 1.178 + p.packages.add(name); 1.179 + } 1.180 + return p; 1.181 + } 1.182 + 1.183 + private static void initProfilesFromProperties(String path) throws IOException { 1.184 + Properties props = new Properties(); 1.185 + try (FileReader reader = new FileReader(path)) { 1.186 + props.load(reader); 1.187 + } 1.188 + for (Profile prof : Profile.values()) { 1.189 + int i = prof.profile; 1.190 + String key = props.getProperty("profile." + i + ".name"); 1.191 + if (key == null) { 1.192 + throw new RuntimeException(key + " missing in " + path); 1.193 + } 1.194 + String n = props.getProperty("profile." + i + ".packages"); 1.195 + String[] pkgs = n.split("\\s+"); 1.196 + for (String p : pkgs) { 1.197 + if (p.isEmpty()) continue; 1.198 + prof.packages.add(p); 1.199 + } 1.200 + } 1.201 + } 1.202 + } 1.203 + 1.204 + // for debugging 1.205 + public static void main(String[] args) { 1.206 + if (args.length == 0) { 1.207 + if (Profile.getProfileCount() == 0) { 1.208 + System.err.println("No profile is present in this JDK"); 1.209 + } 1.210 + for (Profile p : Profile.values()) { 1.211 + String profileName = p.name; 1.212 + SortedSet<String> set = new TreeSet<>(p.packages); 1.213 + for (String s : set) { 1.214 + // filter out the inner classes that are not annotated with 1.215 + // the profile annotation 1.216 + if (PackageToProfile.map.get(s) == p) { 1.217 + System.out.format("%2d: %-10s %s%n", p.profile, profileName, s); 1.218 + profileName = ""; 1.219 + } else { 1.220 + System.err.format("Split package: %s in %s and %s %n", 1.221 + s, PackageToProfile.map.get(s).name, p.name); 1.222 + } 1.223 + } 1.224 + } 1.225 + } 1.226 + for (String pn : args) { 1.227 + System.out.format("%s in %s%n", pn, getProfile(pn)); 1.228 + } 1.229 + } 1.230 +}