--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JRTIndex.java Wed Dec 03 14:25:46 2014 +0000
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.javac.file;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.ref.SoftReference;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import javax.tools.FileObject;
+
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
+import com.sun.tools.javac.nio.PathFileObject;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * A package-oriented index into the jrt: filesystem.
+ */
+public class JRTIndex {
+ /** Get a shared instance of the cache. */
+ private static JRTIndex sharedInstance;
+ public synchronized static JRTIndex getSharedInstance() {
+ if (sharedInstance == null) {
+ try {
+ sharedInstance = new JRTIndex();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ return sharedInstance;
+ }
+
+ /** Get a context-specific instance of a cache. */
+ public static JRTIndex instance(Context context) {
+ try {
+ JRTIndex instance = context.get(JRTIndex.class);
+ if (instance == null)
+ context.put(JRTIndex.class, instance = new JRTIndex());
+ return instance;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static boolean isAvailable() {
+ for (FileSystemProvider p: FileSystemProvider.installedProviders()) {
+ if (p.getScheme().equals("jrt"))
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * The jrt: file system.
+ */
+ private final FileSystem jrtfs;
+
+ /**
+ * The set of module directories within the jrt: file system.
+ */
+ private final Set<Path> jrtModules;
+
+ /**
+ * A lazily evaluated set of entries about the contents of the jrt: file system.
+ */
+ private final Map<RelativeDirectory, SoftReference<Entry>> entries;
+
+ /**
+ * An entry provides cached info about a specific package directory within jrt:.
+ */
+ class Entry {
+ /**
+ * The regular files for this package.
+ * For now, assume just one instance of each file across all modules.
+ */
+ final Map<String, Path> files;
+
+ /**
+ * The set of subdirectories in jrt: for this package.
+ */
+ final Set<RelativeDirectory> subdirs;
+
+ /**
+ * The info that used to be in ct.sym for classes in this package.
+ */
+ final CtSym ctSym;
+
+ private Entry(Map<String, Path> files, Set<RelativeDirectory> subdirs, CtSym ctSym) {
+ this.files = files;
+ this.subdirs = subdirs;
+ this.ctSym = ctSym;
+ }
+ }
+
+ /**
+ * The info that used to be in ct.sym for classes in a package.
+ */
+ public static class CtSym {
+ /**
+ * The classes in this package are internal and not visible.
+ */
+ public final boolean hidden;
+ /**
+ * The classes in this package are proprietary and will generate a warning.
+ */
+ public final boolean proprietary;
+ /**
+ * The minimum profile in which classes in this package are available.
+ */
+ public final String minProfile;
+
+ CtSym(boolean hidden, boolean proprietary, String minProfile) {
+ this.hidden = hidden;
+ this.proprietary = proprietary;
+ this.minProfile = minProfile;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CtSym[");
+ boolean needSep = false;
+ if (hidden) {
+ sb.append("hidden");
+ needSep = true;
+ }
+ if (proprietary) {
+ if (needSep) sb.append(",");
+ sb.append("proprietary");
+ needSep = true;
+ }
+ if (minProfile != null) {
+ if (needSep) sb.append(",");
+ sb.append(minProfile);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ static final CtSym EMPTY = new CtSym(false, false, null);
+ }
+
+ /**
+ * Create and initialize the index.
+ */
+ private JRTIndex() throws IOException {
+ jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
+ jrtModules = new LinkedHashSet<>();
+ Path root = jrtfs.getPath("/");
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(root)) {
+ for (Path entry: stream) {
+ if (Files.isDirectory(entry))
+ jrtModules.add(entry);
+ }
+ }
+ entries = new HashMap<>();
+ }
+
+ public CtSym getCtSym(CharSequence packageName) throws IOException {
+ return getEntry(RelativeDirectory.forPackage(packageName)).ctSym;
+ }
+
+ synchronized Entry getEntry(RelativeDirectory rd) throws IOException {
+ SoftReference<Entry> ref = entries.get(rd);
+ Entry e = (ref == null) ? null : ref.get();
+ if (e == null) {
+ Map<String, Path> files = new LinkedHashMap<>();
+ Set<RelativeDirectory> subdirs = new LinkedHashSet<>();
+ for (Path module: jrtModules) {
+ Path p = rd.getFile(module);
+ if (!Files.exists(p))
+ continue;
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(p)) {
+ for (Path entry: stream) {
+ String name = entry.getFileName().toString();
+ if (Files.isRegularFile(entry)) {
+ // TODO: consider issue of files with same name in different modules
+ files.put(name, entry);
+ } else if (Files.isDirectory(entry)) {
+ subdirs.add(new RelativeDirectory(rd, name));
+ }
+ }
+ }
+ }
+ e = new Entry(Collections.unmodifiableMap(files),
+ Collections.unmodifiableSet(subdirs),
+ getCtInfo(rd));
+ entries.put(rd, new SoftReference<>(e));
+ }
+ return e;
+ }
+
+ public boolean isInJRT(FileObject fo) {
+ if (fo instanceof PathFileObject) {
+ Path path = ((PathFileObject) fo).getPath();
+ return (path.getFileSystem() == jrtfs);
+ } else {
+ return false;
+ }
+ }
+
+ private CtSym getCtInfo(RelativeDirectory dir) {
+ if (dir.path.isEmpty())
+ return CtSym.EMPTY;
+ // It's a side-effect of the default build rules that ct.properties
+ // ends up as a resource bundle.
+ if (ctBundle == null) {
+ final String bundleName = "com.sun.tools.javac.resources.ct";
+ ctBundle = ResourceBundle.getBundle(bundleName);
+ }
+ try {
+ String attrs = ctBundle.getString(dir.path.replace('/', '.') + '*');
+ boolean hidden = false;
+ boolean proprietary = false;
+ String minProfile = null;
+ for (String attr: attrs.split(" +", 0)) {
+ switch (attr) {
+ case "hidden":
+ hidden = true;
+ break;
+ case "proprietary":
+ proprietary = true;
+ break;
+ default:
+ minProfile = attr;
+ }
+ }
+ return new CtSym(hidden, proprietary, minProfile);
+ } catch (MissingResourceException e) {
+ return CtSym.EMPTY;
+ }
+
+ }
+
+ private ResourceBundle ctBundle;
+}