src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java

Fri, 18 Jul 2014 10:43:41 -0700

author
mchung
date
Fri, 18 Jul 2014 10:43:41 -0700
changeset 2539
a51b7fd0543b
parent 2538
1e39ae45d8ac
child 2626
9113c7c8d902
permissions
-rw-r--r--

8050804: (jdeps) Recommend supported API to replace use of JDK internal API
Reviewed-by: dfuchs

     1 /*
     2  * Copyright (c) 2012, 2014, 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.jdeps;
    27 import com.sun.tools.classfile.Annotation;
    28 import com.sun.tools.classfile.ClassFile;
    29 import com.sun.tools.classfile.ConstantPool;
    30 import com.sun.tools.classfile.ConstantPoolException;
    31 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
    32 import com.sun.tools.classfile.Dependencies.ClassFileError;
    33 import java.io.IOException;
    34 import java.nio.file.FileVisitResult;
    35 import java.nio.file.Files;
    36 import java.nio.file.Path;
    37 import java.nio.file.Paths;
    38 import java.nio.file.SimpleFileVisitor;
    39 import java.nio.file.attribute.BasicFileAttributes;
    40 import java.util.*;
    42 import static com.sun.tools.classfile.Attribute.*;
    44 /**
    45  * ClassPath for Java SE and JDK
    46  */
    47 class PlatformClassPath {
    48     private static final List<String> NON_PLATFORM_JARFILES =
    49         Arrays.asList("alt-rt.jar", "jfxrt.jar", "ant-javafx.jar", "javafx-mx.jar");
    50     private static final List<Archive> javaHomeArchives = init();
    52     static List<Archive> getArchives() {
    53         return javaHomeArchives;
    54     }
    56     private static List<Archive> init() {
    57         List<Archive> result = new ArrayList<>();
    58         Path home = Paths.get(System.getProperty("java.home"));
    59         try {
    60             if (home.endsWith("jre")) {
    61                 // jar files in <javahome>/jre/lib
    62                 result.addAll(addJarFiles(home.resolve("lib")));
    63                 if (home.getParent() != null) {
    64                     // add tools.jar and other JDK jar files
    65                     Path lib = home.getParent().resolve("lib");
    66                     if (Files.exists(lib)) {
    67                         result.addAll(addJarFiles(lib));
    68                     }
    69                 }
    70             } else if (Files.exists(home.resolve("lib"))) {
    71                 // either a JRE or a jdk build image
    72                 Path classes = home.resolve("classes");
    73                 if (Files.isDirectory(classes)) {
    74                     // jdk build outputdir
    75                     result.add(new JDKArchive(classes));
    76                 }
    77                 // add other JAR files
    78                 result.addAll(addJarFiles(home.resolve("lib")));
    79             } else {
    80                 throw new RuntimeException("\"" + home + "\" not a JDK home");
    81             }
    82             return result;
    83         } catch (IOException e) {
    84             throw new Error(e);
    85         }
    86     }
    88     private static List<Archive> addJarFiles(final Path root) throws IOException {
    89         final List<Archive> result = new ArrayList<>();
    90         final Path ext = root.resolve("ext");
    91         Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
    92             @Override
    93             public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
    94                 throws IOException
    95             {
    96                 if (dir.equals(root) || dir.equals(ext)) {
    97                     return FileVisitResult.CONTINUE;
    98                 } else {
    99                     // skip other cobundled JAR files
   100                     return FileVisitResult.SKIP_SUBTREE;
   101                 }
   102             }
   103             @Override
   104             public FileVisitResult visitFile(Path p, BasicFileAttributes attrs)
   105                 throws IOException
   106             {
   107                 String fn = p.getFileName().toString();
   108                 if (fn.endsWith(".jar")) {
   109                     // JDK may cobundle with JavaFX that doesn't belong to any profile
   110                     // Treat jfxrt.jar as regular Archive
   111                     result.add(NON_PLATFORM_JARFILES.contains(fn)
   112                                    ? Archive.getInstance(p)
   113                                    : new JDKArchive(p));
   114                 }
   115                 return FileVisitResult.CONTINUE;
   116             }
   117         });
   118         return result;
   119     }
   121     /**
   122      * A JDK archive is part of the JDK containing the Java SE API
   123      * or implementation classes (i.e. JDK internal API)
   124      */
   125     static class JDKArchive extends Archive {
   126         private static List<String> PROFILE_JARS = Arrays.asList("rt.jar", "jce.jar");
   127         public static boolean isProfileArchive(Archive archive) {
   128             if (archive instanceof JDKArchive) {
   129                 return PROFILE_JARS.contains(archive.getName());
   130             }
   131             return false;
   132         }
   134         private final Map<String,Boolean> exportedPackages = new HashMap<>();
   135         private final Map<String,Boolean> exportedTypes = new HashMap<>();
   136         JDKArchive(Path p) throws IOException {
   137             super(p, ClassFileReader.newInstance(p));
   138         }
   140         /**
   141          * Tests if a given fully-qualified name is an exported type.
   142          */
   143         public boolean isExported(String cn) {
   144             int i = cn.lastIndexOf('.');
   145             String pn = i > 0 ? cn.substring(0, i) : "";
   147             boolean isJdkExported = isExportedPackage(pn);
   148             if (exportedTypes.containsKey(cn)) {
   149                 return exportedTypes.get(cn);
   150             }
   151             return isJdkExported;
   152         }
   154         /**
   155          * Tests if a given package name is exported.
   156          */
   157         public boolean isExportedPackage(String pn) {
   158             if (Profile.getProfile(pn) != null) {
   159                 return true;
   160             }
   161             return exportedPackages.containsKey(pn) ? exportedPackages.get(pn) : false;
   162         }
   164         private static final String JDK_EXPORTED_ANNOTATION = "Ljdk/Exported;";
   165         private Boolean isJdkExported(ClassFile cf) throws ConstantPoolException {
   166             RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute)
   167                     cf.attributes.get(RuntimeVisibleAnnotations);
   168             if (attr != null) {
   169                 for (int i = 0; i < attr.annotations.length; i++) {
   170                     Annotation ann = attr.annotations[i];
   171                     String annType = cf.constant_pool.getUTF8Value(ann.type_index);
   172                     if (JDK_EXPORTED_ANNOTATION.equals(annType)) {
   173                         boolean isJdkExported = true;
   174                         for (int j = 0; j < ann.num_element_value_pairs; j++) {
   175                             Annotation.element_value_pair pair = ann.element_value_pairs[j];
   176                             Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) pair.value;
   177                             ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info)
   178                                     cf.constant_pool.get(ev.const_value_index);
   179                             isJdkExported = info.value != 0;
   180                         }
   181                         return Boolean.valueOf(isJdkExported);
   182                     }
   183                 }
   184             }
   185             return null;
   186         }
   188         void processJdkExported(ClassFile cf) throws IOException {
   189             try {
   190                 String cn = cf.getName();
   191                 String pn = cn.substring(0, cn.lastIndexOf('/')).replace('/', '.');
   193                 Boolean b = isJdkExported(cf);
   194                 if (b != null) {
   195                     exportedTypes.put(cn.replace('/', '.'), b);
   196                 }
   197                 if (!exportedPackages.containsKey(pn)) {
   198                     // check if package-info.class has @jdk.Exported
   199                     Boolean isJdkExported = null;
   200                     ClassFile pcf = reader().getClassFile(cn.substring(0, cn.lastIndexOf('/')+1) + "package-info");
   201                     if (pcf != null) {
   202                         isJdkExported = isJdkExported(pcf);
   203                     }
   204                     if (isJdkExported != null) {
   205                         exportedPackages.put(pn, isJdkExported);
   206                     }
   207                 }
   208             } catch (ConstantPoolException e) {
   209                 throw new ClassFileError(e);
   210             }
   211         }
   212     }
   213 }

mercurial