1 /*
   2  * Copyright (c) 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 
  26 package com.sun.tools.javac.platform;
  27 
  28 import java.io.IOException;
  29 import java.nio.file.DirectoryStream;
  30 import java.nio.file.FileSystem;
  31 import java.nio.file.FileSystems;
  32 import java.nio.file.Files;
  33 import java.nio.file.Path;
  34 import java.nio.file.Paths;
  35 import java.nio.file.ProviderNotFoundException;
  36 import java.util.ArrayList;
  37 import java.util.Collection;
  38 import java.util.Collections;
  39 import java.util.HashMap;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Set;
  43 import java.util.TreeSet;
  44 
  45 import javax.annotation.processing.Processor;
  46 
  47 import com.sun.source.util.Plugin;
  48 import com.sun.tools.javac.jvm.Target;
  49 
  50 /** PlatformProvider for JDK N.
  51  *
  52  *  <p><b>This is NOT part of any supported API.
  53  *  If you write code that depends on this, you do so at your own risk.
  54  *  This code and its internal interfaces are subject to change or
  55  *  deletion without notice.</b>
  56  */
  57 public class JDKPlatformProvider implements PlatformProvider {
  58 
  59     @Override
  60     public Iterable<String> getSupportedPlatformNames() {
  61         return SUPPORTED_JAVA_PLATFORM_VERSIONS;
  62     }
  63 
  64     @Override
  65     public PlatformDescription getPlatform(String platformName, String options) {
  66         return new PlatformDescriptionImpl(platformName);
  67     }
  68 
  69     private static final String[] symbolFileLocation = { "lib", "ct.sym" };
  70 
  71     private static final Set<String> SUPPORTED_JAVA_PLATFORM_VERSIONS;
  72 
  73     static {
  74         SUPPORTED_JAVA_PLATFORM_VERSIONS = new TreeSet<>();
  75         Path ctSymFile = findCtSym();
  76         if (Files.exists(ctSymFile)) {
  77             try (FileSystem fs = FileSystems.newFileSystem(ctSymFile, null);
  78                  DirectoryStream<Path> dir =
  79                          Files.newDirectoryStream(fs.getRootDirectories().iterator().next())) {
  80                 for (Path section : dir) {
  81                     for (char ver : section.getFileName().toString().toCharArray()) {
  82                         String verString = Character.toString(ver);
  83                         Target t = Target.lookup(verString);
  84 
  85                         if (t != null) {
  86                             SUPPORTED_JAVA_PLATFORM_VERSIONS.add(targetNumericVersion(t));
  87                         }
  88                     }
  89                 }
  90             } catch (IOException | ProviderNotFoundException ex) {
  91             }
  92         }
  93         SUPPORTED_JAVA_PLATFORM_VERSIONS.add(targetNumericVersion(Target.DEFAULT));
  94     }
  95 
  96     private static String targetNumericVersion(Target target) {
  97         return Integer.toString(target.ordinal() - Target.JDK1_1.ordinal() + 1);
  98     }
  99 
 100     static class PlatformDescriptionImpl implements PlatformDescription {
 101 
 102         private final Map<Path, FileSystem> ctSym2FileSystem = new HashMap<>();
 103         private final String version;
 104 
 105         PlatformDescriptionImpl(String version) {
 106             this.version = version;
 107         }
 108 
 109         @Override
 110         public Collection<Path> getPlatformPath() {
 111             if (Target.lookup(version) == Target.DEFAULT) {
 112                 return null;
 113             }
 114 
 115             List<Path> paths = new ArrayList<>();
 116             Path file = findCtSym();
 117             // file == ${jdk.home}/lib/ct.sym
 118             if (Files.exists(file)) {
 119                 FileSystem fs = ctSym2FileSystem.get(file);
 120                 if (fs == null) {
 121                     try {
 122                         ctSym2FileSystem.put(file, fs = FileSystems.newFileSystem(file, null));
 123                     } catch (IOException ex) {
 124                         throw new IllegalStateException(ex);
 125                     }
 126                 }
 127                 Path root = fs.getRootDirectories().iterator().next();
 128                 try (DirectoryStream<Path> dir = Files.newDirectoryStream(root)) {
 129                     for (Path section : dir) {
 130                         if (section.getFileName().toString().contains(version)) {
 131                             paths.add(section);
 132                         }
 133                     }
 134                 } catch (IOException ex) {
 135                     throw new IllegalStateException(ex);
 136                 }
 137             } else {
 138                 throw new IllegalStateException("Cannot find ct.sym!");
 139             }
 140             return paths;
 141         }
 142 
 143         @Override
 144         public String getSourceVersion() {
 145             return version;
 146         }
 147 
 148         @Override
 149         public String getTargetVersion() {
 150             return version;
 151         }
 152 
 153         @Override
 154         public List<PluginInfo<Processor>> getAnnotationProcessors() {
 155             return Collections.emptyList();
 156         }
 157 
 158         @Override
 159         public List<PluginInfo<Plugin>> getPlugins() {
 160             return Collections.emptyList();
 161         }
 162 
 163         @Override
 164         public List<String> getAdditionalOptions() {
 165             return Collections.emptyList();
 166         }
 167 
 168         @Override
 169         public void close() throws IOException {
 170             for (FileSystem fs : ctSym2FileSystem.values()) {
 171                 fs.close();
 172             }
 173             ctSym2FileSystem.clear();
 174         }
 175 
 176     }
 177 
 178     static Path findCtSym() {
 179         String javaHome = System.getProperty("java.home");
 180         Path file = Paths.get(javaHome);
 181         // file == ${jdk.home}
 182         for (String name : symbolFileLocation)
 183             file = file.resolve(name);
 184         return file;
 185     }
 186 
 187 }