1 /*
   2  * Copyright (c) 2006, 2013, 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.javac.sym;
  26 
  27 import java.io.BufferedInputStream;
  28 import java.io.BufferedWriter;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.FileWriter;
  32 import java.io.IOException;
  33 import java.nio.charset.Charset;
  34 import java.nio.file.Files;
  35 import java.util.HashMap;
  36 import java.util.Map;
  37 import java.util.Properties;
  38 import java.util.Set;
  39 import java.util.TreeMap;
  40 import java.util.TreeSet;
  41 
  42 import com.sun.tools.javac.util.Assert;
  43 
  44 /**
  45  * Provide details about profile contents.
  46  *
  47  * <p><b>This is NOT part of any supported API.
  48  * If you write code that depends on this, you do so at your own
  49  * risk.  This code and its internal interfaces are subject to change
  50  * or deletion without notice.</b></p>
  51  */
  52 public abstract class Profiles {
  53     // for debugging
  54     public static void main(String[] args) throws IOException {
  55         Profiles p = Profiles.read(new File(args[0]));
  56         if (args.length >= 2) {
  57             Map<Integer,Set<String>> lists = new TreeMap<Integer,Set<String>>();
  58             for (int i = 1; i <= 4; i++)
  59                 lists.put(i, new TreeSet<String>());
  60 
  61             File rt_jar_lst = new File(args[1]);
  62             for (String line: Files.readAllLines(rt_jar_lst.toPath(), Charset.defaultCharset())) {
  63                 if (line.endsWith(".class")) {
  64                     String type = line.substring(0, line.length() - 6);
  65                     int profile = p.getProfile(type);
  66                     for (int i = profile; i <= 4; i++)
  67                         lists.get(i).add(type);
  68                 }
  69             }
  70 
  71             for (int i = 1; i <= 4; i++) {
  72                 BufferedWriter out = new BufferedWriter(new FileWriter(i + ".txt"));
  73                 try {
  74                     for (String type: lists.get(i)) {
  75                         out.write(type);
  76                         out.newLine();
  77                     }
  78                 } finally {
  79                     out.close();
  80                 }
  81             }
  82         }
  83     }
  84 
  85     public static Profiles read(File file) throws IOException {
  86         BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
  87         try {
  88             Properties p = new Properties();
  89             p.load(in);
  90             if (p.containsKey("java/lang/Object"))
  91                 return new SimpleProfiles(p);
  92             else
  93                 return new MakefileProfiles(p);
  94         } finally {
  95             in.close();
  96         }
  97     }
  98 
  99     public abstract int getProfileCount();
 100 
 101     public abstract int getProfile(String typeName);
 102 
 103     public abstract Set<String> getPackages(int profile);
 104 
 105     private static class MakefileProfiles extends Profiles {
 106         static class Package {
 107             final Package parent;
 108             final String name;
 109 
 110             Map<String, Package> subpackages = new TreeMap<String, Package>();
 111 
 112             int profile;
 113             Map<String, Integer> includedTypes = new TreeMap<String,Integer>();
 114             Map<String, Integer> excludedTypes = new TreeMap<String,Integer>();
 115 
 116             Package(Package parent, String name) {
 117                 this.parent = parent;
 118                 this.name = name;
 119             }
 120 
 121             int getProfile() {
 122                 return (parent == null) ? profile : Math.max(parent.getProfile(), profile);
 123             }
 124 
 125             int getProfile(String simpleTypeName) {
 126                 Integer i;
 127                 if ((i = includedTypes.get(simpleTypeName)) != null)
 128                     return i;
 129                 if ((i = includedTypes.get("*")) != null)
 130                     return i;
 131                 if ((i = excludedTypes.get(simpleTypeName)) != null)
 132                     return i + 1;
 133                 if ((i = excludedTypes.get("*")) != null)
 134                     return i + 1;
 135                 return getProfile();
 136             }
 137 
 138             String getName() {
 139                 return (parent == null) ? name : (parent.getName() + "/" + name);
 140             }
 141 
 142             void getPackages(int profile, Set<String> results) {
 143                 int prf = getProfile();
 144                 if (prf != 0 && profile >= prf)
 145                     results.add(getName());
 146                 for (Package pkg: subpackages.values())
 147                     pkg.getPackages(profile, results);
 148             }
 149         }
 150 
 151         final static Map<String, Package> packages = new TreeMap<String, Package>();
 152         int maxProfile;
 153 
 154         MakefileProfiles(Properties p) {
 155             int profile = 1;
 156             while (true) {
 157                 String inclPackages = p.getProperty("PROFILE_" + profile + "_RTJAR_INCLUDE_PACKAGES");
 158                 if (inclPackages == null)
 159                     break;
 160                 for (String pkg: inclPackages.substring(1).trim().split("\\s+")) {
 161                     if (pkg.endsWith("/"))
 162                         pkg = pkg.substring(0, pkg.length() - 1);
 163                     includePackage(profile, pkg);
 164                 }
 165                 String inclTypes =  p.getProperty("PROFILE_" + profile + "_RTJAR_INCLUDE_TYPES");
 166                 if (inclTypes != null) {
 167                     for (String type: inclTypes.replace("$$", "$").split("\\s+")) {
 168                         if (type.endsWith(".class"))
 169                             includeType(profile, type.substring(0, type.length() - 6));
 170                     }
 171                 }
 172                 String exclTypes =  p.getProperty("PROFILE_" + profile + "_RTJAR_EXCLUDE_TYPES");
 173                 if (exclTypes != null) {
 174                     for (String type: exclTypes.replace("$$", "$").split("\\s+")) {
 175                         if (type.endsWith(".class"))
 176                             excludeType(profile, type.substring(0, type.length() - 6));
 177                     }
 178                 }
 179                 maxProfile = profile;
 180                 profile++;
 181             }
 182         }
 183 
 184         @Override
 185         public int getProfileCount() {
 186             return maxProfile;
 187         }
 188 
 189         @Override
 190         public int getProfile(String typeName) {
 191             int sep = typeName.lastIndexOf("/");
 192             String packageName = typeName.substring(0, sep);
 193             String simpleName = typeName.substring(sep + 1);
 194 
 195             Package p = getPackage(packageName);
 196             return p.getProfile(simpleName);
 197         }
 198 
 199         @Override
 200         public Set<String> getPackages(int profile) {
 201             Set<String> results = new TreeSet<String>();
 202             for (Package p: packages.values())
 203                 p.getPackages(profile, results);
 204             return results;
 205         }
 206 
 207         private void includePackage(int profile, String packageName) {
 208 //            System.err.println("include package " + packageName);
 209             Package p = getPackage(packageName);
 210             Assert.check(p.profile == 0);
 211             p.profile = profile;
 212         }
 213 
 214         private void includeType(int profile, String typeName) {
 215 //            System.err.println("include type " + typeName);
 216             int sep = typeName.lastIndexOf("/");
 217             String packageName = typeName.substring(0, sep);
 218             String simpleName = typeName.substring(sep + 1);
 219 
 220             Package p = getPackage(packageName);
 221             Assert.check(!p.includedTypes.containsKey(simpleName));
 222             p.includedTypes.put(simpleName, profile);
 223         }
 224 
 225         private void excludeType(int profile, String typeName) {
 226 //            System.err.println("exclude type " + typeName);
 227             int sep = typeName.lastIndexOf("/");
 228             String packageName = typeName.substring(0, sep);
 229             String simpleName = typeName.substring(sep + 1);
 230 
 231             Package p = getPackage(packageName);
 232             Assert.check(!p.excludedTypes.containsKey(simpleName));
 233             p.excludedTypes.put(simpleName, profile);
 234         }
 235 
 236         private Package getPackage(String packageName) {
 237             int sep = packageName.lastIndexOf("/");
 238             Package parent;
 239             Map<String, Package> parentSubpackages;
 240             String simpleName;
 241             if (sep == -1) {
 242                 parent = null;
 243                 parentSubpackages = packages;
 244                 simpleName = packageName;
 245             } else {
 246                 parent = getPackage(packageName.substring(0, sep));
 247                 parentSubpackages = parent.subpackages;
 248                 simpleName = packageName.substring(sep + 1);
 249             }
 250 
 251             Package p = parentSubpackages.get(simpleName);
 252             if (p == null) {
 253                 parentSubpackages.put(simpleName, p = new Package(parent, simpleName));
 254             }
 255             return p;
 256         }
 257     }
 258 
 259     private static class SimpleProfiles extends Profiles {
 260         private final Map<String, Integer> map;
 261         private final int profileCount;
 262 
 263         SimpleProfiles(Properties p) {
 264             int max = 0;
 265             map = new HashMap<String, Integer>();
 266             for (Map.Entry<Object,Object> e: p.entrySet()) {
 267                 String typeName = (String) e.getKey();
 268                 int profile = Integer.valueOf((String) e.getValue());
 269                 map.put(typeName, profile);
 270                 max = Math.max(max, profile);
 271             }
 272             profileCount = max;
 273         }
 274 
 275         @Override
 276         public int getProfileCount() {
 277             return profileCount;
 278         }
 279 
 280         @Override
 281         public int getProfile(String typeName) {
 282             return map.get(typeName);
 283         }
 284 
 285         @Override
 286         public Set<String> getPackages(int profile) {
 287             Set<String> results = new TreeSet<String>();
 288             for (Map.Entry<String,Integer> e: map.entrySet()) {
 289                 String tn = e.getKey();
 290                 int prf = e.getValue();
 291                 int sep = tn.lastIndexOf("/");
 292                 if (sep > 0 && profile >= prf)
 293                     results.add(tn);
 294             }
 295             return results;
 296         }
 297     }
 298 }