1 /*
   2  * Copyright (c) 2006, 2012, 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 
  26 package com.sun.tools.javac.sym;
  27 
  28 import com.sun.tools.javac.api.JavacTaskImpl;
  29 import com.sun.tools.javac.code.Kinds;
  30 import com.sun.tools.javac.code.Scope;
  31 import com.sun.tools.javac.code.Symbol.*;
  32 import com.sun.tools.javac.code.Symbol;
  33 import com.sun.tools.javac.code.Attribute;
  34 import com.sun.tools.javac.code.Symtab;
  35 import com.sun.tools.javac.code.Type;
  36 import com.sun.tools.javac.code.Types;
  37 import com.sun.tools.javac.jvm.ClassWriter;
  38 import com.sun.tools.javac.jvm.Pool;
  39 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
  40 import com.sun.tools.javac.util.List;
  41 import com.sun.tools.javac.util.Names;
  42 import com.sun.tools.javac.util.Pair;
  43 
  44 import java.io.File;
  45 import java.io.IOException;
  46 import java.util.ArrayList;
  47 import java.util.EnumSet;
  48 import java.util.Enumeration;
  49 import java.util.HashSet;
  50 import java.util.Map;
  51 import java.util.ResourceBundle;
  52 import java.util.Set;
  53 
  54 import javax.annotation.processing.AbstractProcessor;
  55 import javax.annotation.processing.RoundEnvironment;
  56 import javax.annotation.processing.SupportedAnnotationTypes;
  57 import javax.annotation.processing.SupportedOptions;
  58 import javax.lang.model.SourceVersion;
  59 import javax.lang.model.element.ElementKind;
  60 import javax.lang.model.element.TypeElement;
  61 import javax.tools.Diagnostic;
  62 import javax.tools.JavaCompiler;
  63 import javax.tools.JavaFileManager.Location;
  64 import javax.tools.JavaFileObject;
  65 import static javax.tools.JavaFileObject.Kind.CLASS;
  66 import javax.tools.StandardJavaFileManager;
  67 import javax.tools.StandardLocation;
  68 import javax.tools.ToolProvider;
  69 
  70 /**
  71  * Used to generate a "symbol file" representing rt.jar that only
  72  * includes supported or legacy proprietary API.  Valid annotation
  73  * processor options:
  74  *
  75  * <dl>
  76  * <dt>com.sun.tools.javac.sym.Jar</dt>
  77  * <dd>Specifies the location of rt.jar.</dd>
  78  * <dt>com.sun.tools.javac.sym.Dest</dt>
  79  * <dd>Specifies the destination directory.</dd>
  80  * </dl>
  81  *
  82  * <p><b>This is NOT part of any supported API.
  83  * If you write code that depends on this, you do so at your own
  84  * risk.  This code and its internal interfaces are subject to change
  85  * or deletion without notice.</b></p>
  86  *
  87  * @author Peter von der Ah\u00e9
  88  */
  89 @SupportedOptions({
  90     "com.sun.tools.javac.sym.Jar",
  91     "com.sun.tools.javac.sym.Dest",
  92     "com.sun.tools.javac.sym.Profiles"})
  93 @SupportedAnnotationTypes("*")
  94 public class CreateSymbols extends AbstractProcessor {
  95 
  96     static Set<String> getLegacyPackages() {
  97         ResourceBundle legacyBundle
  98             = ResourceBundle.getBundle("com.sun.tools.javac.resources.legacy");
  99         Set<String> keys = new HashSet<String>();
 100         for (Enumeration<String> e = legacyBundle.getKeys(); e.hasMoreElements(); )
 101             keys.add(e.nextElement());
 102         return keys;
 103     }
 104 
 105     public boolean process(Set<? extends TypeElement> tes, RoundEnvironment renv) {
 106         try {
 107             if (renv.processingOver())
 108                 createSymbols();
 109         } catch (IOException e) {
 110             processingEnv.getMessager()
 111                 .printMessage(Diagnostic.Kind.ERROR, e.getLocalizedMessage());
 112         } catch (Throwable t) {
 113             t.printStackTrace();
 114             Throwable cause = t.getCause();
 115             if (cause == null)
 116                 cause = t;
 117             processingEnv.getMessager()
 118                 .printMessage(Diagnostic.Kind.ERROR, cause.getLocalizedMessage());
 119         }
 120         return true;
 121     }
 122 
 123     void createSymbols() throws IOException {
 124         Set<String> legacy = getLegacyPackages();
 125         Set<String> legacyProprietary = getLegacyPackages();
 126         Set<String> documented = new HashSet<String>();
 127         Set<PackageSymbol> packages =
 128             ((JavacProcessingEnvironment)processingEnv).getSpecifiedPackages();
 129         Map<String,String> pOptions = processingEnv.getOptions();
 130         String jarName = pOptions.get("com.sun.tools.javac.sym.Jar");
 131         if (jarName == null)
 132             throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Jar=LOCATION_OF_JAR");
 133         String destName = pOptions.get("com.sun.tools.javac.sym.Dest");
 134         if (destName == null)
 135             throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Dest=LOCATION_OF_JAR");
 136         String profileSpec=pOptions.get("com.sun.tools.javac.sym.Profiles");
 137         if (profileSpec == null)
 138             throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Profiles=PROFILES_SPEC");
 139         Profiles profiles = Profiles.read(new File(profileSpec));
 140 
 141         for (PackageSymbol psym : packages) {
 142             String name = psym.getQualifiedName().toString();
 143             legacyProprietary.remove(name);
 144             documented.add(name);
 145         }
 146 
 147         JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
 148         StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
 149         Location jarLocation = StandardLocation.locationFor(jarName);
 150         File jarFile = new File(jarName);
 151         fm.setLocation(jarLocation, List.of(jarFile));
 152         fm.setLocation(StandardLocation.CLASS_PATH, List.<File>nil());
 153         fm.setLocation(StandardLocation.SOURCE_PATH, List.<File>nil());
 154         {
 155             ArrayList<File> bootClassPath = new ArrayList<File>();
 156             bootClassPath.add(jarFile);
 157             for (File path : fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) {
 158                 if (!new File(path.getName()).equals(new File("rt.jar")))
 159                     bootClassPath.add(path);
 160             }
 161             System.err.println("Using boot class path = " + bootClassPath);
 162             fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath);
 163         }
 164         // System.out.println(fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH));
 165         File destDir = new File(destName);
 166         if (!destDir.exists())
 167             if (!destDir.mkdirs())
 168                 throw new RuntimeException("Could not create " + destDir);
 169         fm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(destDir));
 170         Set<String> hiddenPackages = new HashSet<String>();
 171         Set<String> crisp = new HashSet<String>();
 172         List<String> options = List.of("-XDdev");
 173         // options = options.prepend("-doe");
 174         // options = options.prepend("-verbose");
 175         JavacTaskImpl task = (JavacTaskImpl)
 176             tool.getTask(null, fm, null, options, null, null);
 177         com.sun.tools.javac.main.JavaCompiler compiler =
 178             com.sun.tools.javac.main.JavaCompiler.instance(task.getContext());
 179         ClassWriter writer = ClassWriter.instance(task.getContext());
 180         Symtab syms = Symtab.instance(task.getContext());
 181         Names names = Names.instance(task.getContext());
 182         Attribute.Compound proprietaryAnno =
 183             new Attribute.Compound(syms.proprietaryType,
 184                                    List.<Pair<Symbol.MethodSymbol,Attribute>>nil());
 185         Attribute.Compound[] profileAnnos = new Attribute.Compound[profiles.getProfileCount() + 1];
 186         Symbol.MethodSymbol profileValue = (MethodSymbol) syms.profileType.tsym.members().lookup(names.value).sym; 
 187         for (int i = 1; i < profileAnnos.length; i++) {
 188             profileAnnos[i] = new Attribute.Compound(syms.profileType,
 189                     List.<Pair<Symbol.MethodSymbol, Attribute>>of(
 190                     new Pair<Symbol.MethodSymbol, Attribute>(profileValue, new Attribute.Constant(syms.intType, i))));
 191         }
 192 
 193         Type.moreInfo = true;
 194         Types types = Types.instance(task.getContext());
 195         Pool pool = new Pool(types);
 196         for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) {
 197             String className = fm.inferBinaryName(jarLocation, file);
 198             int index = className.lastIndexOf('.');
 199             String pckName = index == -1 ? "" : className.substring(0, index);
 200             boolean addLegacyAnnotation = false;
 201             if (documented.contains(pckName)) {
 202                 if (!legacy.contains(pckName))
 203                     crisp.add(pckName);
 204                 // System.out.println("Documented: " + className);
 205             } else if (legacyProprietary.contains(pckName)) {
 206                 addLegacyAnnotation = true;
 207                 // System.out.println("Legacy proprietary: " + className);
 208             } else {
 209                 // System.out.println("Hidden " + className);
 210                 hiddenPackages.add(pckName);
 211                 continue;
 212             }
 213             TypeSymbol sym = (TypeSymbol)compiler.resolveIdent(className);
 214             if (sym.kind != Kinds.TYP) {
 215                 if (className.indexOf('$') < 0) {
 216                     System.err.println("Ignoring (other) " + className + " : " + sym);
 217                     System.err.println("   " + sym.getClass().getSimpleName() + " " + sym.type);
 218                 }
 219                 continue;
 220             }
 221             sym.complete();
 222             if (sym.getEnclosingElement().getKind() != ElementKind.PACKAGE) {
 223                 System.err.println("Ignoring (bad) " + sym.getQualifiedName());
 224                 continue;
 225             }
 226             ClassSymbol cs = (ClassSymbol) sym;
 227             if (addLegacyAnnotation) {
 228                 cs.annotations.prepend(List.of(proprietaryAnno));
 229             }
 230             int p = profiles.getProfile(cs.fullname.toString().replace(".", "/"));
 231             if (0 < p && p < profileAnnos.length)
 232                 cs.annotations.prepend(List.of(profileAnnos[p]));
 233             writeClass(pool, cs, writer);
 234         }
 235 
 236         if (false) {
 237             for (String pckName : crisp)
 238                 System.out.println("Crisp: " + pckName);
 239             for (String pckName : hiddenPackages)
 240                 System.out.println("Hidden: " + pckName);
 241             for (String pckName : legacyProprietary)
 242                 System.out.println("Legacy proprietary: " + pckName);
 243             for (String pckName : documented)
 244                 System.out.println("Documented: " + pckName);
 245         }
 246     }
 247 
 248     void writeClass(final Pool pool, final ClassSymbol cs, final ClassWriter writer)
 249         throws IOException
 250     {
 251         try {
 252             pool.reset();
 253             cs.pool = pool;
 254             writer.writeClass(cs);
 255             for (Scope.Entry e = cs.members().elems; e != null; e = e.sibling) {
 256                 if (e.sym.kind == Kinds.TYP) {
 257                     ClassSymbol nestedClass = (ClassSymbol)e.sym;
 258                     nestedClass.complete();
 259                     writeClass(pool, nestedClass, writer);
 260                 }
 261             }
 262         } catch (ClassWriter.StringOverflow ex) {
 263             throw new RuntimeException(ex);
 264         } catch (ClassWriter.PoolOverflow ex) {
 265             throw new RuntimeException(ex);
 266         }
 267     }
 268 
 269     public SourceVersion getSupportedSourceVersion() {
 270         return SourceVersion.latest();
 271     }
 272 
 273     // used for debugging
 274     public static void main(String... args) {
 275         String rt_jar = args[0];
 276         String dest = args[1];
 277         args = new String[] {
 278             "-Xbootclasspath:" + rt_jar,
 279             "-XDprocess.packages",
 280             "-proc:only",
 281             "-processor",
 282             "com.sun.tools.javac.sym.CreateSymbols",
 283             "-Acom.sun.tools.javac.sym.Jar=" + rt_jar,
 284             "-Acom.sun.tools.javac.sym.Dest=" + dest,
 285             // <editor-fold defaultstate="collapsed">
 286             "java.applet",
 287             "java.awt",
 288             "java.awt.color",
 289             "java.awt.datatransfer",
 290             "java.awt.dnd",
 291             "java.awt.event",
 292             "java.awt.font",
 293             "java.awt.geom",
 294             "java.awt.im",
 295             "java.awt.im.spi",
 296             "java.awt.image",
 297             "java.awt.image.renderable",
 298             "java.awt.print",
 299             "java.beans",
 300             "java.beans.beancontext",
 301             "java.io",
 302             "java.lang",
 303             "java.lang.annotation",
 304             "java.lang.instrument",
 305             "java.lang.management",
 306             "java.lang.ref",
 307             "java.lang.reflect",
 308             "java.math",
 309             "java.net",
 310             "java.nio",
 311             "java.nio.channels",
 312             "java.nio.channels.spi",
 313             "java.nio.charset",
 314             "java.nio.charset.spi",
 315             "java.rmi",
 316             "java.rmi.activation",
 317             "java.rmi.dgc",
 318             "java.rmi.registry",
 319             "java.rmi.server",
 320             "java.security",
 321             "java.security.acl",
 322             "java.security.cert",
 323             "java.security.interfaces",
 324             "java.security.spec",
 325             "java.sql",
 326             "java.text",
 327             "java.text.spi",
 328             "java.util",
 329             "java.util.concurrent",
 330             "java.util.concurrent.atomic",
 331             "java.util.concurrent.locks",
 332             "java.util.jar",
 333             "java.util.logging",
 334             "java.util.prefs",
 335             "java.util.regex",
 336             "java.util.spi",
 337             "java.util.zip",
 338             "javax.accessibility",
 339             "javax.activation",
 340             "javax.activity",
 341             "javax.annotation",
 342             "javax.annotation.processing",
 343             "javax.crypto",
 344             "javax.crypto.interfaces",
 345             "javax.crypto.spec",
 346             "javax.imageio",
 347             "javax.imageio.event",
 348             "javax.imageio.metadata",
 349             "javax.imageio.plugins.jpeg",
 350             "javax.imageio.plugins.bmp",
 351             "javax.imageio.spi",
 352             "javax.imageio.stream",
 353             "javax.jws",
 354             "javax.jws.soap",
 355             "javax.lang.model",
 356             "javax.lang.model.element",
 357             "javax.lang.model.type",
 358             "javax.lang.model.util",
 359             "javax.management",
 360             "javax.management.loading",
 361             "javax.management.monitor",
 362             "javax.management.relation",
 363             "javax.management.openmbean",
 364             "javax.management.timer",
 365             "javax.management.modelmbean",
 366             "javax.management.remote",
 367             "javax.management.remote.rmi",
 368             "javax.naming",
 369             "javax.naming.directory",
 370             "javax.naming.event",
 371             "javax.naming.ldap",
 372             "javax.naming.spi",
 373             "javax.net",
 374             "javax.net.ssl",
 375             "javax.print",
 376             "javax.print.attribute",
 377             "javax.print.attribute.standard",
 378             "javax.print.event",
 379             "javax.rmi",
 380             "javax.rmi.CORBA",
 381             "javax.rmi.ssl",
 382             "javax.script",
 383             "javax.security.auth",
 384             "javax.security.auth.callback",
 385             "javax.security.auth.kerberos",
 386             "javax.security.auth.login",
 387             "javax.security.auth.spi",
 388             "javax.security.auth.x500",
 389             "javax.security.cert",
 390             "javax.security.sasl",
 391             "javax.sound.sampled",
 392             "javax.sound.sampled.spi",
 393             "javax.sound.midi",
 394             "javax.sound.midi.spi",
 395             "javax.sql",
 396             "javax.sql.rowset",
 397             "javax.sql.rowset.serial",
 398             "javax.sql.rowset.spi",
 399             "javax.swing",
 400             "javax.swing.border",
 401             "javax.swing.colorchooser",
 402             "javax.swing.filechooser",
 403             "javax.swing.event",
 404             "javax.swing.table",
 405             "javax.swing.text",
 406             "javax.swing.text.html",
 407             "javax.swing.text.html.parser",
 408             "javax.swing.text.rtf",
 409             "javax.swing.tree",
 410             "javax.swing.undo",
 411             "javax.swing.plaf",
 412             "javax.swing.plaf.basic",
 413             "javax.swing.plaf.metal",
 414             "javax.swing.plaf.multi",
 415             "javax.swing.plaf.synth",
 416             "javax.tools",
 417             "javax.transaction",
 418             "javax.transaction.xa",
 419             "javax.xml.parsers",
 420             "javax.xml.bind",
 421             "javax.xml.bind.annotation",
 422             "javax.xml.bind.annotation.adapters",
 423             "javax.xml.bind.attachment",
 424             "javax.xml.bind.helpers",
 425             "javax.xml.bind.util",
 426             "javax.xml.soap",
 427             "javax.xml.ws",
 428             "javax.xml.ws.handler",
 429             "javax.xml.ws.handler.soap",
 430             "javax.xml.ws.http",
 431             "javax.xml.ws.soap",
 432             "javax.xml.ws.spi",
 433             "javax.xml.transform",
 434             "javax.xml.transform.sax",
 435             "javax.xml.transform.dom",
 436             "javax.xml.transform.stax",
 437             "javax.xml.transform.stream",
 438             "javax.xml",
 439             "javax.xml.crypto",
 440             "javax.xml.crypto.dom",
 441             "javax.xml.crypto.dsig",
 442             "javax.xml.crypto.dsig.dom",
 443             "javax.xml.crypto.dsig.keyinfo",
 444             "javax.xml.crypto.dsig.spec",
 445             "javax.xml.datatype",
 446             "javax.xml.validation",
 447             "javax.xml.namespace",
 448             "javax.xml.xpath",
 449             "javax.xml.stream",
 450             "javax.xml.stream.events",
 451             "javax.xml.stream.util",
 452             "org.ietf.jgss",
 453             "org.omg.CORBA",
 454             "org.omg.CORBA.DynAnyPackage",
 455             "org.omg.CORBA.ORBPackage",
 456             "org.omg.CORBA.TypeCodePackage",
 457             "org.omg.stub.java.rmi",
 458             "org.omg.CORBA.portable",
 459             "org.omg.CORBA_2_3",
 460             "org.omg.CORBA_2_3.portable",
 461             "org.omg.CosNaming",
 462             "org.omg.CosNaming.NamingContextExtPackage",
 463             "org.omg.CosNaming.NamingContextPackage",
 464             "org.omg.SendingContext",
 465             "org.omg.PortableServer",
 466             "org.omg.PortableServer.CurrentPackage",
 467             "org.omg.PortableServer.POAPackage",
 468             "org.omg.PortableServer.POAManagerPackage",
 469             "org.omg.PortableServer.ServantLocatorPackage",
 470             "org.omg.PortableServer.portable",
 471             "org.omg.PortableInterceptor",
 472             "org.omg.PortableInterceptor.ORBInitInfoPackage",
 473             "org.omg.Messaging",
 474             "org.omg.IOP",
 475             "org.omg.IOP.CodecFactoryPackage",
 476             "org.omg.IOP.CodecPackage",
 477             "org.omg.Dynamic",
 478             "org.omg.DynamicAny",
 479             "org.omg.DynamicAny.DynAnyPackage",
 480             "org.omg.DynamicAny.DynAnyFactoryPackage",
 481             "org.w3c.dom",
 482             "org.w3c.dom.events",
 483             "org.w3c.dom.bootstrap",
 484             "org.w3c.dom.ls",
 485             "org.xml.sax",
 486             "org.xml.sax.ext",
 487             "org.xml.sax.helpers",
 488             "com.sun.java.browser.dom",
 489             "org.w3c.dom",
 490             "org.w3c.dom.bootstrap",
 491             "org.w3c.dom.ls",
 492             "org.w3c.dom.ranges",
 493             "org.w3c.dom.traversal",
 494             "org.w3c.dom.html",
 495             "org.w3c.dom.stylesheets",
 496             "org.w3c.dom.css",
 497             "org.w3c.dom.events",
 498             "org.w3c.dom.views",
 499             "com.sun.management",
 500             "com.sun.security.auth",
 501             "com.sun.security.auth.callback",
 502             "com.sun.security.auth.login",
 503             "com.sun.security.auth.module",
 504             "com.sun.security.jgss",
 505             "com.sun.net.httpserver",
 506             "com.sun.net.httpserver.spi",
 507             "javax.smartcardio"
 508             // </editor-fold>
 509         };
 510         com.sun.tools.javac.Main.compile(args);
 511     }
 512 
 513 }