--- a/langtools/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Thu Feb 23 13:28:55 2017 -0800
+++ b/langtools/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Fri Feb 24 15:23:14 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2017, 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
@@ -142,6 +142,17 @@
* files in the {@linkplain java.nio.file.FileSystems#getDefault() default file system.}
* It is recommended that implementations should support Path objects from any filesystem.</p>
*
+ *
+ * @apiNote
+ * Some methods on this interface take a {@code Collection<? extends Path>}
+ * instead of {@code Iterable<? extends Path>}.
+ * This is to prevent the possibility of accidentally calling the method
+ * with a single {@code Path} as such an argument, because although
+ * {@code Path} implements {@code Iterable<Path>}, it would almost never be
+ * correct to call these methods with a single {@code Path} and have it be treated as
+ * an {@code Iterable} of its components.
+ *
+ *
* @author Peter von der Ahé
* @since 1.6
*/
@@ -266,6 +277,10 @@
* Associates the given search path with the given location. Any
* previous value will be discarded.
*
+ * If the location is a module-oriented or output location, any module-specific
+ * associations set up by {@linkplain #setLocationForModule setLocationForModule}
+ * will be cancelled.
+ *
* @param location a location
* @param files a list of files, if {@code null} use the default
* search path for this location
@@ -279,24 +294,18 @@
throws IOException;
/**
- * Associates the given search path with the given location. Any
- * previous value will be discarded.
+ * Associates the given search path with the given location.
+ * Any previous value will be discarded.
*
- * @apiNote
- * The type of the {@code paths} parameter is a {@code Collection}
- * and not {@code Iterable}. This is to prevent the possibility of
- * accidentally calling the method with a single {@code Path} as
- * the second argument, because although {@code Path} implements
- * {@code Iterable<Path>}, it would almost never be correct to call
- * this method with a single {@code Path} and have it be treated as
- * an {@code Iterable} of its components.
- *
+ * If the location is a module-oriented or output location, any module-specific
+ * associations set up by {@linkplain #setLocationForModule setLocationForModule}
+ * will be cancelled.
*
* @implSpec
* The default implementation converts each path to a file and calls
* {@link #getJavaFileObjectsFromFiles getJavaObjectsFromFiles}.
- * IllegalArgumentException will be thrown if any of the paths
- * cannot be converted to a file.
+ * {@linkplain IllegalArgumentException IllegalArgumentException}
+ * will be thrown if any of the paths cannot be converted to a file.
*
* @param location a location
* @param paths a list of paths, if {@code null} use the default
@@ -316,6 +325,37 @@
}
/**
+ * Associates the given search path with the given module and location,
+ * which must be a module-oriented or output location.
+ * Any previous value will be discarded.
+ * This overrides any default association derived from the search path
+ * associated with the location itself.
+ *
+ * All such module-specific associations will be cancelled if a
+ * new search path is associated with the location by calling
+ * {@linkplain #setLocation setLocation } or
+ * {@linkplain #setLocationFromPaths setLocationFromPaths}.
+ *
+ * @throws IllegalStateException if the location is not a module-oriented
+ * or output location.
+ * @throws UnsupportedOperationException if this operation is not supported by
+ * this file manager.
+ * @throws IOException if {@code location} is an output location and
+ * {@code paths} does not represent an existing directory
+ *
+ * @param location the location
+ * @param moduleName the name of the module
+ * @param paths the search path to associate with the location and module.
+ *
+ * @see setLocation
+ * @see setLocationFromPaths
+ */
+ default void setLocationForModule(Location location, String moduleName,
+ Collection<? extends Path> paths) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Returns the search path associated with the given location.
*
* @param location a location
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Feb 23 13:28:55 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Feb 24 15:23:14 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -1005,6 +1005,14 @@
}
@Override @DefinedBy(Api.COMPILER)
+ public void setLocationForModule(Location location, String moduleName, Collection<? extends Path> paths)
+ throws IOException {
+ nullCheck(location);
+ checkModuleOrientedOrOutputLocation(location);
+ locations.setLocationForModule(location, nullCheck(moduleName), nullCheck(paths));
+ }
+
+ @Override @DefinedBy(Api.COMPILER)
public String inferModuleName(Location location) {
checkNotModuleOrientedLocation(location);
return locations.inferModuleName(location);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Thu Feb 23 13:28:55 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Fri Feb 24 15:23:14 2017 -0800
@@ -398,7 +398,7 @@
* @see #initHandlers
* @see #getHandler
*/
- protected abstract class LocationHandler {
+ protected static abstract class LocationHandler {
/**
* @see JavaFileManager#handleOption
@@ -420,7 +420,13 @@
/**
* @see StandardJavaFileManager#setLocation
*/
- abstract void setPaths(Iterable<? extends Path> files) throws IOException;
+ abstract void setPaths(Iterable<? extends Path> paths) throws IOException;
+
+ /**
+ * @see StandardJavaFileManager#setLocationForModule
+ */
+ abstract void setPathsForModule(String moduleName, Iterable<? extends Path> paths)
+ throws IOException;
/**
* @see JavaFileManager#getLocationForModule(Location, String)
@@ -454,7 +460,7 @@
/**
* A LocationHandler for a given Location, and associated set of options.
*/
- private abstract class BasicLocationHandler extends LocationHandler {
+ private static abstract class BasicLocationHandler extends LocationHandler {
final Location location;
final Set<Option> options;
@@ -473,6 +479,36 @@
? EnumSet.noneOf(Option.class)
: EnumSet.copyOf(Arrays.asList(options));
}
+
+ @Override
+ void setPathsForModule(String moduleName, Iterable<? extends Path> files) throws IOException {
+ // should not happen: protected by check in JavacFileManager
+ throw new UnsupportedOperationException("not supported for " + location);
+ }
+
+ protected Path checkSingletonDirectory(Iterable<? extends Path> paths) throws IOException {
+ Iterator<? extends Path> pathIter = paths.iterator();
+ if (!pathIter.hasNext()) {
+ throw new IllegalArgumentException("empty path for directory");
+ }
+ Path path = pathIter.next();
+ if (pathIter.hasNext()) {
+ throw new IllegalArgumentException("path too long for directory");
+ }
+ checkDirectory(path);
+ return path;
+ }
+
+ protected Path checkDirectory(Path path) throws IOException {
+ Objects.requireNonNull(path);
+ if (!Files.exists(path)) {
+ throw new FileNotFoundException(path + ": does not exist");
+ }
+ if (!Files.isDirectory(path)) {
+ throw new IOException(path + ": not a directory");
+ }
+ return path;
+ }
}
/**
@@ -483,8 +519,7 @@
private class OutputLocationHandler extends BasicLocationHandler {
private Path outputDir;
- private Map<String, Location> moduleLocations;
- private Map<Path, Location> pathLocations;
+ private ModuleTable moduleTable;
OutputLocationHandler(Location location, Option... options) {
super(location, options);
@@ -510,51 +545,51 @@
}
@Override
- void setPaths(Iterable<? extends Path> files) throws IOException {
- if (files == null) {
+ void setPaths(Iterable<? extends Path> paths) throws IOException {
+ if (paths == null) {
outputDir = null;
} else {
- Iterator<? extends Path> pathIter = files.iterator();
- if (!pathIter.hasNext()) {
- throw new IllegalArgumentException("empty path for directory");
- }
- Path dir = pathIter.next();
- if (pathIter.hasNext()) {
- throw new IllegalArgumentException("path too long for directory");
- }
- if (!Files.exists(dir)) {
- throw new FileNotFoundException(dir + ": does not exist");
- } else if (!Files.isDirectory(dir)) {
- throw new IOException(dir + ": not a directory");
- }
- outputDir = dir;
+ outputDir = checkSingletonDirectory(paths);
}
- moduleLocations = null;
- pathLocations = null;
+ moduleTable = null;
+ listed = false;
}
@Override
Location getLocationForModule(String name) {
- if (moduleLocations == null) {
- moduleLocations = new HashMap<>();
- pathLocations = new HashMap<>();
+ if (moduleTable == null) {
+ moduleTable = new ModuleTable();
}
- Location l = moduleLocations.get(name);
+ ModuleLocationHandler l = moduleTable.get(name);
if (l == null) {
Path out = outputDir.resolve(name);
- l = new ModuleLocationHandler(location.getName() + "[" + name + "]",
- name,
- Collections.singleton(out),
- true);
- moduleLocations.put(name, l);
- pathLocations.put(out.toAbsolutePath(), l);
- }
+ l = new ModuleLocationHandler(this, location.getName() + "[" + name + "]",
+ name, Collections.singletonList(out), true);
+ moduleTable.add(l);
+ }
return l;
}
@Override
+ void setPathsForModule(String name, Iterable<? extends Path> paths) throws IOException {
+ Path out = checkSingletonDirectory(paths);
+ if (moduleTable == null) {
+ moduleTable = new ModuleTable();
+ }
+ ModuleLocationHandler l = moduleTable.get(name);
+ if (l == null) {
+ l = new ModuleLocationHandler(this, location.getName() + "[" + name + "]",
+ name, Collections.singletonList(out), true);
+ moduleTable.add(l);
+ } else {
+ l.searchPath = Collections.singletonList(out);
+ moduleTable.updatePaths(l);
+ }
+ }
+
+ @Override
Location getLocationForModule(Path dir) {
- return (pathLocations == null) ? null : pathLocations.get(dir);
+ return (moduleTable == null) ? null : moduleTable.get(dir);
}
private boolean listed;
@@ -569,11 +604,11 @@
}
listed = true;
}
- if (moduleLocations == null)
+
+ if (moduleTable == null || moduleTable.isEmpty())
return Collections.emptySet();
- Set<Location> locns = new LinkedHashSet<>();
- moduleLocations.forEach((k, v) -> locns.add(v));
- return Collections.singleton(locns);
+
+ return Collections.singleton(moduleTable.locations());
}
}
@@ -860,14 +895,16 @@
* The Location can be specified to accept overriding classes from the
* {@code --patch-module <module>=<path> } parameter.
*/
- private class ModuleLocationHandler extends LocationHandler implements Location {
- protected final String name;
- protected final String moduleName;
- protected final Collection<Path> searchPath;
- protected final boolean output;
+ private static class ModuleLocationHandler extends LocationHandler implements Location {
+ private final LocationHandler parent;
+ private final String name;
+ private final String moduleName;
+ private final boolean output;
+ Collection<Path> searchPath;
- ModuleLocationHandler(String name, String moduleName, Collection<Path> searchPath,
- boolean output) {
+ ModuleLocationHandler(LocationHandler parent, String name, String moduleName,
+ Collection<Path> searchPath, boolean output) {
+ this.parent = parent;
this.name = name;
this.moduleName = moduleName;
this.searchPath = searchPath;
@@ -891,21 +928,79 @@
@Override // defined by LocationHandler
Collection<Path> getPaths() {
- // For now, we always return searchPathWithOverrides. This may differ from the
- // JVM behavior if there is a module-info.class to be found in the overriding
- // classes.
- return searchPath;
+ return Collections.unmodifiableCollection(searchPath);
}
@Override // defined by LocationHandler
- void setPaths(Iterable<? extends Path> files) throws IOException {
- throw new UnsupportedOperationException();
+ void setPaths(Iterable<? extends Path> paths) throws IOException {
+ // defer to the parent to determine if this is acceptable
+ parent.setPathsForModule(moduleName, paths);
+ }
+
+ @Override // defined by LocationHandler
+ void setPathsForModule(String moduleName, Iterable<? extends Path> paths) {
+ throw new UnsupportedOperationException("not supported for " + name);
}
@Override // defined by LocationHandler
String inferModuleName() {
return moduleName;
}
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ /**
+ * A table of module location handlers, indexed by name and path.
+ */
+ private static class ModuleTable {
+ private final Map<String, ModuleLocationHandler> nameMap = new LinkedHashMap<>();
+ private final Map<Path, ModuleLocationHandler> pathMap = new LinkedHashMap<>();
+
+ void add(ModuleLocationHandler h) {
+ nameMap.put(h.moduleName, h);
+ for (Path p : h.searchPath) {
+ pathMap.put(p.toAbsolutePath().normalize(), h);
+ }
+ }
+
+ void updatePaths(ModuleLocationHandler h) {
+ // use iterator, to be able to remove old entries
+ for (Iterator<Map.Entry<Path, ModuleLocationHandler>> iter = pathMap.entrySet().iterator();
+ iter.hasNext(); ) {
+ Map.Entry<Path, ModuleLocationHandler> e = iter.next();
+ if (e.getValue() == h) {
+ iter.remove();
+ }
+ }
+ for (Path p : h.searchPath) {
+ pathMap.put(p.toAbsolutePath().normalize(), h);
+ }
+ }
+
+ ModuleLocationHandler get(String name) {
+ return nameMap.get(name);
+ }
+
+ ModuleLocationHandler get(Path path) {
+ return pathMap.get(path);
+ }
+
+ void clear() {
+ nameMap.clear();
+ pathMap.clear();
+ }
+
+ boolean isEmpty() {
+ return nameMap.isEmpty();
+ }
+
+ Set<Location> locations() {
+ return Collections.unmodifiableSet(nameMap.values().stream().collect(Collectors.toSet()));
+ }
}
/**
@@ -913,7 +1008,7 @@
* like UPGRADE_MODULE_PATH and MODULE_PATH.
*/
private class ModulePathLocationHandler extends SimpleLocationHandler {
- private Map<String, ModuleLocationHandler> pathModules;
+ private ModuleTable moduleTable;
ModulePathLocationHandler(Location location, Option... options) {
super(location, options);
@@ -930,8 +1025,8 @@
@Override
public Location getLocationForModule(String moduleName) {
- initPathModules();
- return pathModules.get(moduleName);
+ initModuleLocations();
+ return moduleTable.get(moduleName);
}
@Override
@@ -950,20 +1045,49 @@
}
}
super.setPaths(paths);
+ moduleTable = null;
}
- private void initPathModules() {
- if (pathModules != null) {
+ @Override
+ void setPathsForModule(String name, Iterable<? extends Path> paths) throws IOException {
+ List<Path> checkedPaths = checkPaths(paths);
+ // how far should we go to validate the paths provide a module?
+ // e.g. contain module-info with the correct name?
+ initModuleLocations();
+ ModuleLocationHandler l = moduleTable.get(name);
+ if (l == null) {
+ l = new ModuleLocationHandler(this, location.getName() + "[" + name + "]",
+ name, checkedPaths, true);
+ moduleTable.add(l);
+ } else {
+ l.searchPath = checkedPaths;
+ moduleTable.updatePaths(l);
+ }
+ }
+
+ private List<Path> checkPaths(Iterable<? extends Path> paths) throws IOException {
+ Objects.requireNonNull(paths);
+ List<Path> validPaths = new ArrayList<>();
+ for (Path p : paths) {
+ validPaths.add(checkDirectory(p));
+ }
+ return validPaths;
+ }
+
+ private void initModuleLocations() {
+ if (moduleTable != null) {
return;
}
- pathModules = new LinkedHashMap<>();
+ moduleTable = new ModuleTable();
for (Set<Location> set : listLocationsForModules()) {
for (Location locn : set) {
if (locn instanceof ModuleLocationHandler) {
- ModuleLocationHandler h = (ModuleLocationHandler) locn;
- pathModules.put(h.moduleName, h);
+ ModuleLocationHandler l = (ModuleLocationHandler) locn;
+ if (!moduleTable.nameMap.containsKey(l.moduleName)) {
+ moduleTable.add(l);
+ }
}
}
}
@@ -1052,8 +1176,9 @@
String moduleName = readModuleName(moduleInfoClass);
String name = location.getName()
+ "[" + pathIndex + ":" + moduleName + "]";
- ModuleLocationHandler l = new ModuleLocationHandler(name, moduleName,
- Collections.singleton(path), false);
+ ModuleLocationHandler l = new ModuleLocationHandler(
+ ModulePathLocationHandler.this, name, moduleName,
+ Collections.singletonList(path), false);
return Collections.singleton(l);
} catch (ModuleNameReader.BadClassFile e) {
log.error(Errors.LocnBadModuleInfo(path));
@@ -1077,8 +1202,9 @@
Path modulePath = module.snd;
String name = location.getName()
+ "[" + pathIndex + "." + (index++) + ":" + moduleName + "]";
- ModuleLocationHandler l = new ModuleLocationHandler(name, moduleName,
- Collections.singleton(modulePath), false);
+ ModuleLocationHandler l = new ModuleLocationHandler(
+ ModulePathLocationHandler.this, name, moduleName,
+ Collections.singletonList(modulePath), false);
result.add(l);
}
return result;
@@ -1094,8 +1220,9 @@
Path modulePath = module.snd;
String name = location.getName()
+ "[" + pathIndex + ":" + moduleName + "]";
- ModuleLocationHandler l = new ModuleLocationHandler(name, moduleName,
- Collections.singleton(modulePath), false);
+ ModuleLocationHandler l = new ModuleLocationHandler(
+ ModulePathLocationHandler.this, name, moduleName,
+ Collections.singletonList(modulePath), false);
return Collections.singleton(l);
}
@@ -1212,9 +1339,7 @@
}
private class ModuleSourcePathLocationHandler extends BasicLocationHandler {
-
- private Map<String, Location> moduleLocations;
- private Map<Path, Location> pathLocations;
+ private ModuleTable moduleTable;
ModuleSourcePathLocationHandler() {
super(StandardLocation.MODULE_SOURCE_PATH,
@@ -1233,7 +1358,7 @@
expandBraces(s, segments);
}
- Map<String, Collection<Path>> map = new LinkedHashMap<>();
+ Map<String, List<Path>> map = new LinkedHashMap<>();
final String MARKER = "*";
for (String seg: segments) {
int markStart = seg.indexOf(MARKER);
@@ -1258,13 +1383,12 @@
}
}
- moduleLocations = new LinkedHashMap<>();
- pathLocations = new LinkedHashMap<>();
- map.forEach((k, v) -> {
- String name = location.getName() + "[" + k + "]";
- ModuleLocationHandler h = new ModuleLocationHandler(name, k, v, false);
- moduleLocations.put(k, h);
- v.forEach(p -> pathLocations.put(normalize(p), h));
+ moduleTable = new ModuleTable();
+ map.forEach((modName, modPath) -> {
+ String locnName = location.getName() + "[" + modName + "]";
+ ModuleLocationHandler l = new ModuleLocationHandler(this, locnName, modName,
+ modPath, false);
+ moduleTable.add(l);
});
}
@@ -1273,7 +1397,7 @@
return (ch == File.separatorChar) || (ch == '/');
}
- void add(Map<String, Collection<Path>> map, Path prefix, Path suffix) {
+ void add(Map<String, List<Path>> map, Path prefix, Path suffix) {
if (!Files.isDirectory(prefix)) {
if (warn) {
String key = Files.exists(prefix)
@@ -1288,7 +1412,7 @@
Path path = (suffix == null) ? entry : entry.resolve(suffix);
if (Files.isDirectory(path)) {
String name = entry.getFileName().toString();
- Collection<Path> paths = map.get(name);
+ List<Path> paths = map.get(name);
if (paths == null)
map.put(name, paths = new ArrayList<>());
paths.add(path);
@@ -1364,7 +1488,7 @@
@Override
boolean isSet() {
- return (moduleLocations != null);
+ return (moduleTable != null);
}
@Override
@@ -1378,22 +1502,51 @@
}
@Override
+ void setPathsForModule(String name, Iterable<? extends Path> paths) throws IOException {
+ List<Path> validPaths = checkPaths(paths);
+
+ if (moduleTable == null)
+ moduleTable = new ModuleTable();
+
+ ModuleLocationHandler l = moduleTable.get(name);
+ if (l == null) {
+ l = new ModuleLocationHandler(this,
+ location.getName() + "[" + name + "]",
+ name,
+ validPaths,
+ true);
+ moduleTable.add(l);
+ } else {
+ l.searchPath = validPaths;
+ moduleTable.updatePaths(l);
+ }
+ }
+
+ private List<Path> checkPaths(Iterable<? extends Path> paths) throws IOException {
+ Objects.requireNonNull(paths);
+ List<Path> validPaths = new ArrayList<>();
+ for (Path p : paths) {
+ validPaths.add(checkDirectory(p));
+ }
+ return validPaths;
+ }
+
+ @Override
Location getLocationForModule(String name) {
- return (moduleLocations == null) ? null : moduleLocations.get(name);
+ return (moduleTable == null) ? null : moduleTable.get(name);
}
@Override
Location getLocationForModule(Path dir) {
- return (pathLocations == null) ? null : pathLocations.get(dir);
+ return (moduleTable == null) ? null : moduleTable.get(dir);
}
@Override
Iterable<Set<Location>> listLocationsForModules() {
- if (moduleLocations == null)
+ if (moduleTable == null)
return Collections.emptySet();
- Set<Location> locns = new LinkedHashSet<>();
- moduleLocations.forEach((k, v) -> locns.add(v));
- return Collections.singleton(locns);
+
+ return Collections.singleton(moduleTable.locations());
}
}
@@ -1401,8 +1554,7 @@
private class SystemModulesLocationHandler extends BasicLocationHandler {
private Path systemJavaHome;
private Path modules;
- private Map<String, ModuleLocationHandler> systemModules;
- private Map<Path, Location> pathLocations;
+ private ModuleTable moduleTable;
SystemModulesLocationHandler() {
super(StandardLocation.SYSTEM_MODULES, Option.SYSTEM);
@@ -1437,23 +1589,38 @@
if (files == null) {
systemJavaHome = null;
} else {
- Iterator<? extends Path> pathIter = files.iterator();
- if (!pathIter.hasNext()) {
- throw new IllegalArgumentException("empty path for directory"); // TODO: FIXME
- }
- Path dir = pathIter.next();
- if (pathIter.hasNext()) {
- throw new IllegalArgumentException("path too long for directory"); // TODO: FIXME
- }
- if (!Files.exists(dir)) {
- throw new FileNotFoundException(dir + ": does not exist");
- } else if (!Files.isDirectory(dir)) {
- throw new IOException(dir + ": not a directory");
- }
+ Path dir = checkSingletonDirectory(files);
update(dir);
}
}
+ @Override
+ void setPathsForModule(String name, Iterable<? extends Path> paths) throws IOException {
+ List<Path> checkedPaths = checkPaths(paths);
+ initSystemModules();
+ ModuleLocationHandler l = moduleTable.get(name);
+ if (l == null) {
+ l = new ModuleLocationHandler(this,
+ location.getName() + "[" + name + "]",
+ name,
+ checkedPaths,
+ true);
+ moduleTable.add(l);
+ } else {
+ l.searchPath = checkedPaths;
+ moduleTable.updatePaths(l);
+ }
+ }
+
+ private List<Path> checkPaths(Iterable<? extends Path> paths) throws IOException {
+ Objects.requireNonNull(paths);
+ List<Path> validPaths = new ArrayList<>();
+ for (Path p : paths) {
+ validPaths.add(checkDirectory(p));
+ }
+ return validPaths;
+ }
+
private void update(Path p) {
if (!isCurrentPlatform(p) && !Files.exists(p.resolve("lib").resolve("jrt-fs.jar")) &&
!Files.exists(systemJavaHome.resolve("modules")))
@@ -1473,31 +1640,27 @@
@Override
Location getLocationForModule(String name) throws IOException {
initSystemModules();
- return systemModules.get(name);
+ return moduleTable.get(name);
}
@Override
Location getLocationForModule(Path dir) throws IOException {
initSystemModules();
- return (pathLocations == null) ? null : pathLocations.get(dir);
+ return moduleTable.get(dir);
}
@Override
Iterable<Set<Location>> listLocationsForModules() throws IOException {
initSystemModules();
- Set<Location> locns = new LinkedHashSet<>();
- for (Location l: systemModules.values())
- locns.add(l);
- return Collections.singleton(locns);
+ return Collections.singleton(moduleTable.locations());
}
private void initSystemModules() throws IOException {
- if (systemModules != null) {
+ if (moduleTable != null)
return;
- }
if (systemJavaHome == null) {
- systemModules = Collections.emptyMap();
+ moduleTable = new ModuleTable();
return;
}
@@ -1535,24 +1698,21 @@
}
}
- systemModules = new LinkedHashMap<>();
- pathLocations = new LinkedHashMap<>();
+ moduleTable = new ModuleTable();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules, Files::isDirectory)) {
for (Path entry : stream) {
String moduleName = entry.getFileName().toString();
String name = location.getName() + "[" + moduleName + "]";
- ModuleLocationHandler h = new ModuleLocationHandler(name, moduleName,
- Collections.singleton(entry), false);
- systemModules.put(moduleName, h);
- pathLocations.put(normalize(entry), h);
+ ModuleLocationHandler h = new ModuleLocationHandler(this,
+ name, moduleName, Collections.singletonList(entry), false);
+ moduleTable.add(h);
}
}
}
}
private class PatchModulesLocationHandler extends BasicLocationHandler {
- private final Map<String, ModuleLocationHandler> moduleLocations = new HashMap<>();
- private final Map<Path, Location> pathLocations = new HashMap<>();
+ private final ModuleTable moduleTable = new ModuleTable();
PatchModulesLocationHandler() {
super(StandardLocation.PATCH_MODULE_PATH, Option.PATCH_MODULE);
@@ -1576,11 +1736,9 @@
SearchPath mPatchPath = new SearchPath()
.addFiles(v.substring(eq + 1));
String name = location.getName() + "[" + moduleName + "]";
- ModuleLocationHandler h = new ModuleLocationHandler(name, moduleName, mPatchPath, false);
- moduleLocations.put(moduleName, h);
- for (Path r : mPatchPath) {
- pathLocations.put(normalize(r), h);
- }
+ ModuleLocationHandler h = new ModuleLocationHandler(this, name,
+ moduleName, mPatchPath, false);
+ moduleTable.add(h);
} else {
// Should not be able to get here;
// this should be caught and handled in Option.PATCH_MODULE
@@ -1593,7 +1751,7 @@
@Override
boolean isSet() {
- return !moduleLocations.isEmpty();
+ return !moduleTable.isEmpty();
}
@Override
@@ -1606,24 +1764,25 @@
throw new UnsupportedOperationException();
}
+ @Override // defined by LocationHandler
+ void setPathsForModule(String moduleName, Iterable<? extends Path> files) throws IOException {
+ throw new UnsupportedOperationException(); // not yet
+ }
+
@Override
Location getLocationForModule(String name) throws IOException {
- return moduleLocations.get(name);
+ return moduleTable.get(name);
}
@Override
Location getLocationForModule(Path dir) throws IOException {
- return (pathLocations == null) ? null : pathLocations.get(dir);
+ return moduleTable.get(dir);
}
@Override
Iterable<Set<Location>> listLocationsForModules() throws IOException {
- Set<Location> locns = new LinkedHashSet<>();
- for (Location l: moduleLocations.values())
- locns.add(l);
- return Collections.singleton(locns);
+ return Collections.singleton(moduleTable.locations());
}
-
}
Map<Location, LocationHandler> handlersForLocation;
@@ -1644,7 +1803,6 @@
new OutputLocationHandler(StandardLocation.NATIVE_HEADER_OUTPUT, Option.H),
new ModuleSourcePathLocationHandler(),
new PatchModulesLocationHandler(),
- // TODO: should UPGRADE_MODULE_PATH be merged with SYSTEM_MODULES?
new ModulePathLocationHandler(StandardLocation.UPGRADE_MODULE_PATH, Option.UPGRADE_MODULE_PATH),
new ModulePathLocationHandler(StandardLocation.MODULE_PATH, Option.MODULE_PATH),
new SystemModulesLocationHandler(),
@@ -1704,6 +1862,20 @@
return (h == null ? null : h.getLocationForModule(dir));
}
+ void setLocationForModule(Location location, String moduleName,
+ Iterable<? extends Path> files) throws IOException {
+ LocationHandler h = getHandler(location);
+ if (h == null) {
+ if (location.isOutputLocation()) {
+ h = new OutputLocationHandler(location);
+ } else {
+ h = new ModulePathLocationHandler(location);
+ }
+ handlersForLocation.put(location, h);
+ }
+ h.setPathsForModule(moduleName, files);
+ }
+
String inferModuleName(Location location) {
LocationHandler h = getHandler(location);
return (h == null ? null : h.inferModuleName());
@@ -1737,5 +1909,4 @@
return p.toAbsolutePath().normalize();
}
}
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/file/SetLocationForModule.java Fri Feb 24 15:23:14 2017 -0800
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8173914
+ * @summary JavaFileManager.setLocationForModule
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.main
+ * @library /tools/lib
+ * @build toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox SetLocationForModule
+ * @run main SetLocationForModule
+ */
+
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import toolbox.JavacTask;
+import toolbox.TestRunner;
+import toolbox.TestRunner.Test;
+import toolbox.ToolBox;
+
+public class SetLocationForModule extends TestRunner {
+
+ public static void main(String... args) throws Exception {
+ new SetLocationForModule().runTests(m -> new Object[] { Paths.get(m.getName()) });
+ }
+
+ public SetLocationForModule() {
+ super(System.err);
+ }
+
+ private final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ private final ToolBox tb = new ToolBox();
+
+ @Test
+ public void testBasic(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Location[] locns = {
+ StandardLocation.SOURCE_PATH,
+ StandardLocation.CLASS_PATH,
+ StandardLocation.PLATFORM_CLASS_PATH,
+ };
+ // set a value
+ Path out = Files.createDirectories(base.resolve("out"));
+ for (Location locn : locns) {
+ checkException("unsupported for location",
+ IllegalArgumentException.class,
+ "location is not an output location or a module-oriented location: " + locn,
+ () -> fm.setLocationForModule(locn, "m", List.of(out)));
+ }
+ }
+ }
+
+ @Test
+ public void testModulePath(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Path src = base.resolve("src");
+ Path src_m = src.resolve("m");
+ tb.writeJavaFiles(src_m, "module m { }");
+
+ Location locn = StandardLocation.MODULE_PATH;
+
+ Path modules1 = Files.createDirectories(base.resolve("modules1"));
+ new JavacTask(tb)
+ .outdir(modules1)
+ .options("--module-source-path", src.toString())
+ .files(tb.findJavaFiles(src))
+ .run();
+ fm.setLocationFromPaths(locn, List.of(modules1));
+
+ Location m = fm.getLocationForModule(locn, "m");
+ checkEqual("default setting",
+ fm.getLocationAsPaths(m), modules1.resolve("m"));
+
+ Path override1 = Files.createDirectories(base.resolve("override1"));
+ fm.setLocationForModule(locn, "m", List.of(override1));
+ checkEqual("override setting 1",
+ fm.getLocationAsPaths(m), override1);
+
+ Path override2 = Files.createDirectories(base.resolve("override2"));
+ fm.setLocationFromPaths(m, List.of(override2));
+ checkEqual("override setting 2",
+ fm.getLocationAsPaths(m), override2);
+
+ Path modules2 = Files.createDirectories(base.resolve("modules2"));
+ fm.setLocationFromPaths(locn, List.of(modules2));
+
+ checkEqual("updated setting",
+ fm.getLocationAsPaths(m), modules2.resolve("m"));
+ }
+ }
+
+ @Test
+ public void testModuleSourcePath(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+
+ Location locn = StandardLocation.MODULE_SOURCE_PATH;
+
+ Path src1 = Files.createDirectories(base.resolve("src1"));
+ Path src1_m = src1.resolve("m");
+ tb.writeJavaFiles(src1_m, "module m { }");
+// fm.setLocationFromPaths(locn, List.of(src1));
+ fm.handleOption("--module-source-path", List.of(src1.toString()).iterator());
+
+ Location m = fm.getLocationForModule(locn, "m");
+ checkEqual("default setting",
+ fm.getLocationAsPaths(m), src1.resolve("m"));
+
+ Path override1 = Files.createDirectories(base.resolve("override1"));
+ tb.writeJavaFiles(override1, "module m { }");
+ fm.setLocationForModule(locn, "m", List.of(override1));
+ checkEqual("override setting 1",
+ fm.getLocationAsPaths(m), override1);
+
+ Path override2 = Files.createDirectories(base.resolve("override2"));
+ tb.writeJavaFiles(override2, "module m { }");
+ fm.setLocationFromPaths(m, List.of(override2));
+ checkEqual("override setting 2",
+ fm.getLocationAsPaths(m), override2);
+
+ Path src2 = Files.createDirectories(base.resolve("src2"));
+ Path src2_m = src2.resolve("m");
+ tb.writeJavaFiles(src2_m, "module m { }");
+// fm.setLocationFromPaths(locn, List.of(src2));
+ fm.handleOption("--module-source-path", List.of(src2.toString()).iterator());
+
+ checkEqual("updated setting",
+ fm.getLocationAsPaths(m), src2.resolve("m"));
+ }
+ }
+
+ @Test
+ public void testOutput(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Location locn = StandardLocation.CLASS_OUTPUT;
+
+ Path out1 = Files.createDirectories(base.resolve("out1"));
+ fm.setLocationFromPaths(locn, List.of(out1));
+
+ Location m = fm.getLocationForModule(locn, "m");
+ checkEqual("default setting",
+ fm.getLocationAsPaths(m), out1.resolve("m"));
+
+ Path override1 = Files.createDirectories(base.resolve("override1"));
+ fm.setLocationForModule(locn, "m", List.of(override1));
+ checkEqual("override setting 1",
+ fm.getLocationAsPaths(m), override1);
+
+ Path override2 = Files.createDirectories(base.resolve("override2"));
+ fm.setLocationFromPaths(m, List.of(override2));
+ checkEqual("override setting 2",
+ fm.getLocationAsPaths(m), override2);
+
+ Path out2 = Files.createDirectories(base.resolve("out2"));
+ fm.setLocationFromPaths(locn, List.of(out2));
+
+ checkEqual("updated setting",
+ fm.getLocationAsPaths(m), out2.resolve("m"));
+ }
+ }
+
+ @Test
+ public void testOutput_invalid(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Location locn = StandardLocation.CLASS_OUTPUT;
+ // set a top default
+ Path out1 = Files.createDirectories(base.resolve("out1"));
+ fm.setLocationFromPaths(locn, List.of(out1));
+ // getLocnForModule
+ Location m = fm.getLocationForModule(locn, "m");
+ checkEqual("default setting",
+ fm.getLocationAsPaths(m), out1.resolve("m"));
+
+ checkException("empty arg list",
+ IllegalArgumentException.class, "empty path for directory",
+ () -> fm.setLocationFromPaths(m, Collections.emptyList()));
+
+ Path out2 = Files.createDirectories(base.resolve("out2"));
+ checkException("empty arg list",
+ IllegalArgumentException.class, "path too long for directory",
+ () -> fm.setLocationFromPaths(m, List.of(out2, out2)));
+
+ Path notExist = base.resolve("notExist");
+ checkException("not exist",
+ FileNotFoundException.class, notExist + ": does not exist",
+ () -> fm.setLocationFromPaths(m, List.of(notExist)));
+
+ Path file = Files.createFile(base.resolve("file.txt"));
+ checkException("not exist",
+ IOException.class, file + ": not a directory",
+ () -> fm.setLocationFromPaths(m, List.of(file)));
+ }
+ }
+
+ @Test
+ public void testOutput_nested(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Location locn = StandardLocation.CLASS_OUTPUT;
+
+ Path out1 = Files.createDirectories(base.resolve("out1"));
+ fm.setLocationForModule(locn, "m", List.of(out1));
+
+ Location m = fm.getLocationForModule(locn, "m");
+ checkEqual("initial setting",
+ fm.getLocationAsPaths(m), out1);
+
+ Path out2 = Files.createDirectories(base.resolve("out2"));
+ checkException("create nested module",
+ UnsupportedOperationException.class, "not supported for CLASS_OUTPUT[m]",
+ () -> fm.setLocationForModule(m, "x", List.of(out2)));
+ }
+ }
+
+ @Test
+ public void testSystemModules(Path base) throws IOException {
+ try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
+ Location locn = StandardLocation.SYSTEM_MODULES;
+
+ Location javaCompiler = fm.getLocationForModule(locn, "java.compiler");
+ // cannot easily verify default setting: could be jrt: or exploded image
+
+ Path override1 = Files.createDirectories(base.resolve("override1"));
+ fm.setLocationForModule(locn, "java.compiler", List.of(override1));
+ checkEqual("override setting 1",
+ fm.getLocationAsPaths(javaCompiler), override1);
+
+ Path override2 = Files.createDirectories(base.resolve("override2"));
+ fm.setLocationFromPaths(javaCompiler, List.of(override2));
+ checkEqual("override setting 2",
+ fm.getLocationAsPaths(javaCompiler), override2);
+ }
+ }
+
+ @Test
+ public void testTemplate(Path base) {
+ // set a top default
+ // getLocnForModule
+ // set a value
+ // getLocnForModule
+ // reset
+ // getLocationForModule
+ }
+
+ interface RunnableWithException {
+ public void run() throws Exception;
+ }
+
+ void checkException(String message,
+ Class<? extends Throwable> expectedException, String expectedMessage,
+ RunnableWithException r) {
+ try {
+ r.run();
+ error(message + ": expected exception not thrown: " + expectedException);
+ } catch (Exception | Error t) {
+ if (expectedException.isAssignableFrom(t.getClass())) {
+ checkEqual("exception message",
+ t.getMessage(), expectedMessage);
+
+ } else {
+ error(message + ": unexpected exception\n"
+ + "expect: " + expectedException + "\n"
+ + " found: " + t);
+ }
+ }
+ }
+
+ void checkEqual(String message, Iterable<? extends Path> found, Path... expect) {
+ List<Path> fList = asList(found);
+ List<Path> eList = List.of(expect);
+ if (!Objects.equals(fList, fList)) {
+ error(message + ": lists not equal\n"
+ + "expect: " + eList + "\n"
+ + " found: " + fList);
+ }
+ }
+
+ void checkEqual(String message, String found, String expect) {
+ if (!Objects.equals(found, expect)) {
+ error(message + ": strings not equal\n"
+ + "expect: " + expect + "\n"
+ + " found: " + found);
+ }
+ }
+
+ List<Path> asList(Iterable<? extends Path> a) {
+ List<Path> list = new ArrayList<>();
+ for (Path p : a) {
+ list.add(p);
+ }
+ return list;
+ }
+}
+