blob: 096d2bf2b1ff6c3e1c1223b6e7fe2430f25245bc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.mx.project;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.event.ChangeListener;
import org.netbeans.modules.java.mx.project.suitepy.MxDistribution;
import org.netbeans.modules.java.mx.project.suitepy.MxImports;
import org.netbeans.modules.java.mx.project.suitepy.MxLibrary;
import org.netbeans.modules.java.mx.project.suitepy.MxProject;
import org.netbeans.modules.java.mx.project.suitepy.MxSuite;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.AnnotationProcessingQuery;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.Sources;
import org.netbeans.spi.java.classpath.ClassPathFactory;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.netbeans.spi.java.classpath.FlaggedClassPathImplementation;
import org.netbeans.spi.java.classpath.PathResourceImplementation;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation2;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.openide.util.Exceptions;
import org.openide.util.Utilities;
import java.util.stream.Collectors;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.queries.SourceLevelQuery;
import static org.netbeans.spi.java.classpath.FlaggedClassPathImplementation.PROP_FLAGS;
import org.netbeans.spi.java.queries.MultipleRootsUnitTestForSourceQueryImplementation;
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation2;
import org.netbeans.spi.project.SubprojectProvider;
final class SuiteSources implements Sources,
BinaryForSourceQueryImplementation2<SuiteSources.Group>, SourceForBinaryQueryImplementation2,
SourceLevelQueryImplementation2, SubprojectProvider, MultipleRootsUnitTestForSourceQueryImplementation {
private static final Logger LOG = Logger.getLogger(SuiteSources.class.getName());
private static final SuiteSources CORE;
static {
MxSuite coreSuite = CoreSuite.CORE_5_279_0;
CORE = new SuiteSources(null, null, null, coreSuite);
}
private final MxSuite suite;
private final List<Group> groups;
private final List<Library> libraries;
private final List<Dist> distributions;
private final FileObject dir;
/**
* non-null if the dependencies haven't yet been properly initialized
*/
private Map<String, Dep> transitiveDeps;
/**
* avoid GC of imported projects
*/
private final SuiteProject prj;
private final Map<String, SuiteSources> imported;
private final Jdks jdks;
SuiteSources(SuiteProject owner, Jdks jdks, FileObject dir, MxSuite suite) {
final Map<String, Dep> fillDeps = new HashMap<>();
this.prj = owner;
this.jdks = jdks;
this.dir = dir;
this.groups = findGroups(fillDeps, suite, dir);
this.libraries = findLibraries(fillDeps, suite);
this.imported = findImportedSuites(dir, suite, fillDeps);
this.distributions = findDistributions(suite, this.libraries, this.groups, fillDeps);
this.suite = suite;
this.transitiveDeps = fillDeps;
}
@Override
public String toString() {
return "MxSources[" + (dir == null ? "mx" : dir.toURI()) + "]";
}
private List<Group> findGroups(Map<String, Dep> fillDeps, MxSuite s, FileObject dir) {
List<Group> arr = new ArrayList<>();
for (Map.Entry<String, MxProject> entry : s.projects().entrySet()) {
String name = entry.getKey();
MxProject mxPrj = entry.getValue();
FileObject prjDir = findPrjDir(dir, name, mxPrj);
if (prjDir == null) {
fillDeps.put(name, new Group(name, mxPrj, null, null, null, name, name));
continue;
}
String prevName = null;
Group firstGroup = null;
String binPrefix = "mxbuild/";
for (String rel : mxPrj.sourceDirs()) {
FileObject srcDir = prjDir.getFileObject(rel);
FileObject binDir = getSubDir(dir, binPrefix + name + "/bin");
FileObject srcGenDir = getSubDir(dir, binPrefix + name + "/src_gen");
if (srcDir != null && binDir != null) {
String prgName = name + "-" + rel;
String displayName;
if (prevName == null) {
displayName = name;
} else {
displayName = name + "[" + rel + "]";
}
Group g = new Group(name, mxPrj, srcDir, srcGenDir, binDir, prgName, displayName);
arr.add(g);
if (firstGroup == null) {
firstGroup = g;
}
prevName = displayName;
}
}
if (firstGroup != null) {
fillDeps.put(name, firstGroup);
}
}
return arr;
}
private static FileObject getSubDir(FileObject dir, String relPath) {
FileObject subDir = dir.getFileObject(relPath);
if (subDir == null) {
try {
subDir = FileUtil.createFolder(dir, relPath);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
return subDir;
}
private List<Library> findLibraries(Map<String, Dep> fillDeps, MxSuite suite) {
final Map<String, MxLibrary> allLibraries = new HashMap<>();
registerLibs(allLibraries, null, suite.libraries());
List<Library> arr = new ArrayList<>();
for (Map.Entry<String, MxLibrary> entry : allLibraries.entrySet()) {
final Library library = new Library(entry.getKey(), entry.getValue());
arr.add(library);
fillDeps.put(library.getName(), library);
}
for (Map.Entry<String, MxLibrary> entry : suite.jdklibraries().entrySet()) {
final JdkLibrary library = new JdkLibrary(entry.getKey(), entry.getValue());
arr.add(library);
fillDeps.put(library.getName(), library);
}
return arr;
}
private static Map<String, SuiteSources> findImportedSuites(FileObject dir, MxSuite s, Map<String, Dep> fillDeps) {
if (dir == null) {
return Collections.emptyMap();
}
CORE.registerDeps("mx", fillDeps);
final MxImports imports = s.imports();
if (imports != null) {
Map<String, SuiteSources> imported = new LinkedHashMap<>();
for (MxImports.Suite imp : imports.suites()) {
SuiteSources impSources = findSuiteSources(dir, imp);
final String suiteName = imp.name();
if (impSources == null) {
LOG.log(Level.INFO, "cannot find imported suite: {0}", suiteName);
continue;
}
imported.put(suiteName, impSources);
impSources.registerDeps(suiteName, fillDeps);
}
return imported;
}
return Collections.emptyMap();
}
private List<Dist> findDistributions(MxSuite s, List<Library> libraries, List<Group> groups, Map<String, Dep> fillDeps) {
List<Dist> dists = new ArrayList<>();
for (Map.Entry<String, MxDistribution> entry : s.distributions().entrySet()) {
Dist d = new Dist(entry.getKey(), entry.getValue());
dists.add(d);
fillDeps.put(d.getName(), d);
}
return dists;
}
final synchronized void ensureTransitiveDependenciesAreComputed() {
Map<String, Dep> collectedDeps = this.transitiveDeps;
if (collectedDeps == null) {
return;
}
this.transitiveDeps = null;
for (Library l : this.libraries) {
transitiveDeps(l, collectedDeps);
}
for (Group g : this.groups) {
transitiveDeps(g, collectedDeps);
}
for (Dist d : this.distributions) {
transitiveDeps(d, collectedDeps);
}
for (Group g : groups) {
g.computeClassPath(collectedDeps);
}
for (Dist d : this.distributions) {
d.computeSourceRoots(collectedDeps);
}
}
private static SuiteSources findSuiteSources(FileObject dir, MxImports.Suite imp) throws IllegalArgumentException {
SuiteSources sources = findSuiteSources(dir.getParent(), imp.name());
if (sources != null) {
return sources;
}
if (imp.subdir()) {
for (FileObject subDir : dir.getParent().getChildren()) {
sources = findSuiteSources(subDir, imp.name());
if (sources != null) {
return sources;
}
}
for (FileObject subDir : dir.getParent().getParent().getChildren()) {
sources = findSuiteSources(subDir, imp.name());
if (sources != null) {
return sources;
}
}
}
return null;
}
private static SuiteSources findSuiteSources(FileObject root, String name) throws IllegalArgumentException {
FileObject impDir = root.getFileObject(name);
if (impDir != null) {
try {
Project impPrj = ProjectManager.getDefault().findProject(impDir);
return impPrj == null ? null : impPrj.getLookup().lookup(SuiteSources.class);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
return null;
}
@Override
public SourceGroup[] getSourceGroups(String string) {
return groups();
}
Group[] groups() {
return groups.toArray(new Group[0]);
}
Group findGroup(FileObject fo) {
for (Group g : groups) {
if (g.contains(fo)) {
return g;
}
}
return null;
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void removeChangeListener(ChangeListener cl) {
}
private static FileObject findPrjDir(FileObject dir, String prjName, MxProject prj) {
if (dir == null) {
return null;
}
if (prj.dir() != null) {
return dir.getFileObject(prj.dir());
}
if (prj.subDir() != null) {
dir = dir.getFileObject(prj.subDir());
if (dir == null) {
return null;
}
}
return dir.getFileObject(prjName);
}
private Collection<Dep> transitiveDeps(Dep current, Map<String, Dep> fill) {
current.owner().ensureTransitiveDependenciesAreComputed();
final Collection<Dep> currentAllDeps = current.allDeps();
if (currentAllDeps == Collections.<Dep>emptySet()) {
throw new IllegalStateException("Cyclic dep on " + current.getName());
} else if (currentAllDeps != null) {
return currentAllDeps;
}
current.setAllDeps(Collections.emptySet());
TreeSet<Dep> computing = new TreeSet<>();
computing.add(current);
for (String depName : current.depNames()) {
Dep dep = fill.get(depName);
if (dep == null) {
int colon = depName.lastIndexOf(':');
dep = fill.get(depName.substring(colon + 1));
if (dep == null) {
LOG.log(Level.INFO, "dep not found: {0}", depName);
continue;
}
}
Collection<Dep> allDeps = transitiveDeps(dep, fill);
computing.addAll(allDeps);
}
current.setAllDeps(computing);
return computing;
}
private static void registerLibs(Map<String, MxLibrary> collect, String prefix, Map<String, MxLibrary> libraries) {
for (Map.Entry<String, MxLibrary> entry : libraries.entrySet()) {
String key = entry.getKey();
MxLibrary lib = entry.getValue();
if (prefix == null) {
collect.put(key, lib);
} else {
collect.put(prefix + ":" + key, lib);
}
}
}
private void registerDeps(String prefix, Map<String, Dep> fillDeps) {
for (Library library : libraries) {
fillDeps.put(prefix + ":" + library.getName(), library);
}
for (Dist d : distributions) {
fillDeps.put(prefix + ":" + d.getName(), d);
}
for (Map.Entry<String, SuiteSources> s : imported.entrySet()) {
s.getValue().registerDeps(s.getKey(), fillDeps);
}
}
@Override
public Group findBinaryRoots2(URL url) {
final FileObject srcFo = URLMapper.findFileObject(url);
for (Group group : this.groups) {
if (group.contains(srcFo)) {
return group;
}
}
return null;
}
@Override
public URL[] computeRoots(Group group) {
if (group.binDir != null) {
return new URL[] { group.binDir.toURL() };
} else {
return new URL[0];
}
}
@Override
public boolean computePreferBinaries(Group result) {
return true;
}
@Override
public void computeChangeListener(Group result, boolean bln, ChangeListener cl) {
}
@Override
public SourceForBinaryQueryImplementation2.Result findSourceRoots2(URL url) {
this.ensureTransitiveDependenciesAreComputed();
for (Dist dist : this.distributions) {
if (dist.isRootJar(url)) {
List<FileObject> roots = new ArrayList<>();
for (Group d : dist.getContributingGroups()) {
roots.add(d.srcDir);
roots.add(d.srcGenDir);
}
return new ImmutableResult(roots.toArray(new FileObject[roots.size()]));
}
}
for (Group group : this.groups) {
if (group.binDir != null && group.binDir.toURL().equals(url)) {
return new ImmutableResult(group.srcDir, group.srcGenDir);
}
}
return null;
}
@Override
public SourceForBinaryQuery.Result findSourceRoots(URL url) {
return findSourceRoots2(url);
}
@Override
public SourceLevelQueryImplementation2.Result getSourceLevel(FileObject fo) {
Group g = findGroup(fo);
if (g == null) {
return null;
}
return new SourceLevelQueryImplementation2.Result2() {
@Override
public SourceLevelQuery.Profile getProfile() {
return SourceLevelQuery.Profile.DEFAULT;
}
@Override
public String getSourceLevel() {
return g.getCompliance().getSourceLevel();
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void removeChangeListener(ChangeListener cl) {
}
};
}
@Override
public Set<? extends Project> getSubprojects() {
Set<Project> prjs = new HashSet<>();
for (SuiteSources imp : imported.values()) {
prjs.add(imp.prj);
}
return prjs;
}
@Override
public URL[] findUnitTests(FileObject fo) {
return new URL[0];
}
@Override
public URL[] findSources(FileObject fo) {
Group g = findGroup(fo);
return g == null ? new URL[0] : new URL[] { g.getRootFolder().toURL() };
}
static interface Dep extends Comparable<Dep> {
String getName();
Collection<String> depNames();
Collection<Dep> allDeps();
void setAllDeps(Collection<Dep> set);
@Override
public default int compareTo(Dep o) {
return getName().compareTo(o.getName());
}
SuiteSources owner();
}
abstract class SharedSupport {
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
private Boolean exists;
public final Set<ClassPath.Flag> getFlags() {
return Boolean.TRUE.equals(exists) ? Collections.emptySet() : Collections.singleton(ClassPath.Flag.INCOMPLETE);
}
public void addPropertyChangeListener(PropertyChangeListener pl) {
support.addPropertyChangeListener(pl);
}
public void removePropertyChangeListener(PropertyChangeListener pl) {
support.removePropertyChangeListener(pl);
}
final boolean isInitialized() {
return exists != null;
}
final void updateExists(boolean existsNow) {
if (exists == null) {
exists = existsNow;
} else {
if (exists != existsNow) {
exists = existsNow;
support.firePropertyChange(PROP_FLAGS, !exists, (boolean) exists);
}
}
}
}
final class Dist extends SharedSupport implements Dep, FlaggedClassPathImplementation {
final String name;
final MxDistribution dist;
Collection<Dep> allDeps;
private Collection<Group> groups;
public Dist(String name, MxDistribution dist) {
this.name = name;
this.dist = dist;
}
@Override
public Collection<String> depNames() {
Set<String> deps = new TreeSet<>();
deps.addAll(dist.distDependencies());
deps.addAll(dist.exclude());
return deps;
}
@Override
public Collection<Dep> allDeps() {
return this.allDeps;
}
@Override
public void setAllDeps(Collection<Dep> set) {
this.allDeps = set;
}
@Override
public String getName() {
return this.name;
}
private FileObject getJar() {
if (SuiteSources.this.dir == null) {
return null;
}
FileObject dists = mxBuildDists();
List<FileObject> candidates = findCandidates(dists);
if (candidates.isEmpty()) {
return dists.getFileObject(name.toLowerCase().replace("_", "-") + ".jar", false);
} else {
return candidates.get(0);
}
}
private FileObject mxBuildDists() {
FileObject dists = getSubDir(SuiteSources.this.dir, "mxbuild/dists");
return dists;
}
boolean isRootJar(URL url) {
try {
if (url == null) {
return false;
}
URI uri = url.toURI();
for (FileObject fo : findCandidates(mxBuildDists())) {
if (uri.equals(toJarURL(fo).toURI())) {
return true;
}
}
} catch (MalformedURLException | URISyntaxException ex) {
// ignore
}
return false;
}
private List<FileObject> findCandidates(FileObject dists) {
List<FileObject> candidates = new ArrayList<>();
List<FileObject> dist = Arrays.stream(dists.getChildren()).
filter((fo) -> fo.isFolder() && fo.getName().startsWith("jdk")).
collect(Collectors.toList());
dist.sort((fo1, fo2) -> fo2.getName().compareTo(fo1.getName()));
for (FileObject jdkDir : dist) {
FileObject jar = jdkDir.getFileObject(name.toLowerCase().replace("_", "-") + ".jar");
if (jar != null) {
candidates.add(jar);
}
}
return candidates;
}
@Override
public List<? extends PathResourceImplementation> getResources() {
ensureTransitiveDependenciesAreComputed();
FileObject jar = getJar();
updateExists(jar != null && jar.isData());
if (jar != null) {
PathResourceImplementation res;
try {
res = ClassPathSupport.createResource(getJarRoot());
return Collections.singletonList(res);
} catch (MalformedURLException ex) {
// OK
}
}
return Collections.emptyList();
}
private URL getJarRoot() throws MalformedURLException {
return toJarURL(getJar());
}
private URL toJarURL(FileObject jar) throws MalformedURLException {
if (jar != null) {
return new URL("jar:" + jar.toURL() + "!/");
} else {
return null;
}
}
@Override
public SuiteSources owner() {
return SuiteSources.this;
}
private void computeSourceRoots(Map<String, Dep> collectedDeps) {
if (groups != null) {
return;
}
Set<Group> contributingGroups = new LinkedHashSet<>();
for (String d : this.dist.dependencies()) {
Dep dep = collectedDeps.get(d);
if (dep == null || dep.allDeps() == null) {
continue;
}
for (Dep d2 : dep.allDeps()) {
if (d2 instanceof Group) {
contributingGroups.add((Group) d2);
}
}
}
for (String d : this.dist.distDependencies()) {
final Dep anyDep = collectedDeps.get(d);
if (anyDep instanceof Dist) {
Dist dep = (Dist) anyDep;
dep.computeSourceRoots(collectedDeps);
contributingGroups.removeAll(dep.getContributingGroups());
}
}
groups = contributingGroups;
}
public Collection<Group> getContributingGroups() {
return groups;
}
@Override
public String toString() {
return "Dist[name=" + name + "]";
}
}
final class Group implements SourceGroup, Dep, AnnotationProcessingQuery.Result,
Compliance.Provider {
private final String mxName;
private final MxProject mxPrj;
private final FileObject srcDir;
private final FileObject srcGenDir;
private final FileObject binDir;
private final String name;
private final String displayName;
private final Compliance compliance;
private ClassPath sourceCP;
private ClassPath cp;
private ClassPath processorPath;
private Collection<Dep> allDeps;
private ClassPath bootCP;
private Object platformOrThis;
Group(String mxName, MxProject mxPrj, FileObject srcDir, FileObject srcGenDir, FileObject binDir, String name, String displayName) {
this.mxName = mxName;
this.mxPrj = mxPrj;
this.srcDir = srcDir;
this.srcGenDir = srcGenDir;
this.binDir = binDir;
this.name = name;
this.displayName = displayName;
this.compliance = Compliance.parse(mxPrj.javaCompliance());
}
@Override
public FileObject getRootFolder() {
return srcDir;
}
@Override
public String getName() {
return name;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public Icon getIcon(boolean opened) {
return null;
}
@Override
public Compliance getCompliance() {
return compliance;
}
@Override
public boolean contains(FileObject file) {
if (file == srcDir || file == srcGenDir || FileUtil.isParentOf(srcDir, file) || (srcGenDir != null && FileUtil.isParentOf(srcGenDir, file))) {
return true;
}
return false;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
}
@Override
public String toString() {
return "SuiteSources.Group[name=" + name + ",rootFolder=" + srcDir + "]"; // NOI18N
}
ClassPath getSourceCP() {
ensureTransitiveDependenciesAreComputed();
return sourceCP;
}
ClassPath getCP() {
ensureTransitiveDependenciesAreComputed();
return cp;
}
@Override
public Collection<String> depNames() {
List<String> both = new ArrayList<>();
both.addAll(mxPrj.dependencies());
both.addAll(mxPrj.generatedDependencies());
return both;
}
@Override
public void setAllDeps(Collection<Dep> set) {
allDeps = set;
}
@Override
public Collection<Dep> allDeps() {
return allDeps;
}
private void computeClassPath(Map<String, Dep> transDeps) {
for (Dep d : transDeps.values()) {
d.owner().ensureTransitiveDependenciesAreComputed();
}
List<Group> arr = new ArrayList<>();
List<ClassPathImplementation> libs = new ArrayList<>();
processTransDep(transDeps.get(mxName), arr, libs);
cp = composeClassPath(arr, libs);
List<FileObject> roots = new ArrayList<>();
if (srcDir != null) {
roots.add(srcDir);
}
if (srcGenDir != null) {
roots.add(srcGenDir);
}
sourceCP = ClassPathSupport.createClassPath(roots.toArray(new FileObject[roots.size()]));
if (mxPrj.annotationProcessors().isEmpty()) {
processorPath = null;
} else {
List<Group> groups = new ArrayList<>();
List<ClassPathImplementation> jars = new ArrayList<>();
for (String dep : mxPrj.annotationProcessors()) {
processTransDep(transDeps.get(dep), groups, jars);
}
processorPath = composeClassPath(groups, jars);
}
}
private void processTransDep(Dep dep, List<Group> addGroups, List<ClassPathImplementation> addJars) {
if (dep != null) {
dep.owner().ensureTransitiveDependenciesAreComputed();
for (Dep d : dep.allDeps()) {
if (d == this) {
continue;
}
d.owner().ensureTransitiveDependenciesAreComputed();
if (d instanceof Group) {
addGroups.add((Group) d);
} else if (d instanceof ClassPathImplementation) {
addJars.add((ClassPathImplementation) d);
}
}
}
}
private ClassPath composeClassPath(List<Group> arr, List<ClassPathImplementation> libs) {
Set<FileObject> roots = new LinkedHashSet<>();
final int depsCount = arr.size();
for (int i = 0; i < depsCount; i++) {
final Group g = arr.get(i);
if (g.binDir != null) {
roots.add(g.binDir);
}
}
ClassPath prjCp = ClassPathSupport.createClassPath(roots.toArray(new FileObject[0]));
if (!libs.isEmpty()) {
if (libs.size() == 1) {
prjCp = ClassPathSupport.createProxyClassPath(prjCp,
ClassPathFactory.createClassPath(libs.get(0))
);
} else {
prjCp = ClassPathSupport.createProxyClassPath(prjCp,
ClassPathFactory.createClassPath(
ClassPathSupport.createProxyClassPathImplementation(
libs.toArray(new ClassPathImplementation[0])
)
)
);
}
}
return prjCp;
}
ClassPath getProcessorCP() {
ensureTransitiveDependenciesAreComputed();
return processorPath;
}
@Override
public Set<? extends AnnotationProcessingQuery.Trigger> annotationProcessingEnabled() {
return EnumSet.of(AnnotationProcessingQuery.Trigger.ON_SCAN, AnnotationProcessingQuery.Trigger.IN_EDITOR);
}
@Override
public Iterable<? extends String> annotationProcessorsToRun() {
return null;
}
@Override
public URL sourceOutputDirectory() {
return srcGenDir == null ? null : srcGenDir.toURL();
}
@Override
public Map<? extends String, ? extends String> processorOptions() {
return Collections.emptyMap();
}
@Override
public void addChangeListener(ChangeListener l) {
}
@Override
public void removeChangeListener(ChangeListener l) {
}
@Override
public SuiteSources owner() {
return SuiteSources.this;
}
ClassPath getBootCP() {
if (this.bootCP == null) {
JavaPlatform platform = getJavaPlatform();
if (platform == null) {
platform = JavaPlatform.getDefault();
}
List<ClassPath.Entry> entries = platform.getBootstrapLibraries().entries();
List<URL> roots = new ArrayList<>();
for (ClassPath.Entry entry : entries) {
URL root = entry.getURL();
if (root.getPath().contains("/graal-sdk.jar")) {
continue;
}
if (root.getPath().contains("/graaljs-scriptengine.jar")) {
continue;
}
if (root.getPath().contains("/graal-sdk.src.zip")) {
continue;
}
roots.add(entry.getURL());
}
this.bootCP = ClassPathSupport.createClassPath(roots.toArray(new URL[0]));
}
return this.bootCP;
}
final JavaPlatform getJavaPlatform() {
if (this.platformOrThis == null) {
JavaPlatform p = jdks.find(compliance);
if (p == null) {
this.platformOrThis = this;
} else {
this.platformOrThis = p;
}
}
return this.platformOrThis instanceof JavaPlatform ? (JavaPlatform) this.platformOrThis : null;
}
}
private class Library extends SharedSupport implements FlaggedClassPathImplementation, Dep {
final MxLibrary lib;
final String libName;
Collection<Dep> allDeps;
Library(String libName, MxLibrary lib) {
this.libName = libName;
this.lib = getOSSLibrary(lib);
}
final MxLibrary getOSSLibrary(MxLibrary lib) {
if (lib.sha1() == null && !lib.os_arch().isEmpty()) {
Map<String, MxLibrary.Arch> os_dep_libs = lib.os_arch();
String os = System.getProperty("os.name").toLowerCase();
for (Map.Entry<String, MxLibrary.Arch> entry : os_dep_libs.entrySet()) {
if (os.contains(entry.getKey())) {
return entry.getValue().amd64();
}
}
}
return lib;
}
File getJar(boolean dumpIfMissing) {
File mxCache;
String cache = System.getenv("MX_CACHE_DIR");
if (cache != null) {
mxCache = new File(cache);
} else {
mxCache = new File(new File(new File(System.getProperty("user.home")), ".mx"), "cache");
}
int prefix = libName.indexOf(':');
final String simpleName = libName.substring(prefix + 1);
File simpleJar = null;
if (lib.path() != null && !lib.path().isEmpty()) {
FileObject relativePath = dir.getFileObject(lib.path());
if (relativePath != null) {
simpleJar = FileUtil.toFile(relativePath);
}
}
if (simpleJar == null) {
simpleJar = new File(mxCache, simpleName + "_" + lib.sha1() + ".jar");
}
if (simpleJar.exists()) {
return simpleJar;
}
File dir = new File(mxCache, simpleName + "_" + lib.sha1());
File jar = new File(dir, simpleName.replace('_', '-').toLowerCase(Locale.ENGLISH) + ".jar");
if (dumpIfMissing && !jar.exists()) {
for (File f = jar;; f = f.getParentFile()) {
if (!f.exists()) {
LOG.log(Level.WARNING, "{0} does not exist", f);
} else {
StringBuilder sb = new StringBuilder();
sb.append(f).append(" exists:\n");
String[] kids = f.list();
if (kids != null) {
for (String n : kids) {
sb.append(" ").append(n).append("\n");
}
}
LOG.log(Level.INFO, sb.toString());
break;
}
}
}
return jar;
}
@Override
public String getName() {
return libName;
}
@Override
public Collection<String> depNames() {
return lib.dependencies();
}
@Override
public Collection<Dep> allDeps() {
return allDeps;
}
@Override
public void setAllDeps(Collection<Dep> set) {
this.allDeps = set;
}
@Override
public List<? extends PathResourceImplementation> getResources() {
File jar = getJar(!isInitialized());
updateExists(jar.exists());
PathResourceImplementation res;
try {
res = ClassPathSupport.createResource(new URL("jar:" + Utilities.toURI(jar).toURL() + "!/"));
return Collections.singletonList(res);
} catch (MalformedURLException ex) {
return Collections.emptyList();
}
}
@Override
public SuiteSources owner() {
return SuiteSources.this;
}
}
private class JdkLibrary extends Library {
JdkLibrary(String libName, MxLibrary lib) {
super(libName, lib);
}
@Override
File getJar(boolean dumpIfMissing) {
File first = null;
for (File jdk : jdks.jdks()) {
File jre = new File(jdk, "jre");
File jrePath = new File(jre, lib.path().replace('/', File.separatorChar));
if (jrePath.exists()) {
return jrePath;
}
if (first == null) {
first = jrePath;
}
File jdkPath = new File(jdk, lib.path().replace('/', File.separatorChar));
if (jdkPath.exists()) {
return jdkPath;
}
}
if (dumpIfMissing) {
for (File jdk : jdks.jdks()) {
File libPath = new File(jdk, lib.path().replace('/', File.separatorChar));
if (!libPath.exists()) {
LOG.log(Level.WARNING, "{0} does not exist", libPath);
} else {
StringBuilder sb = new StringBuilder();
sb.append(libPath).append(" exists:\n");
String[] kids = libPath.list();
if (kids != null) {
for (String n : kids) {
sb.append(" ").append(n).append("\n");
}
}
LOG.log(Level.INFO, sb.toString());
break;
}
}
}
return first;
}
@Override
public String getName() {
return libName;
}
@Override
public Collection<String> depNames() {
return lib.dependencies();
}
@Override
public Collection<Dep> allDeps() {
return allDeps;
}
@Override
public void setAllDeps(Collection<Dep> set) {
this.allDeps = set;
}
@Override
public List<? extends PathResourceImplementation> getResources() {
File jar = getJar(isInitialized());
updateExists(jar.exists());
PathResourceImplementation res;
try {
res = ClassPathSupport.createResource(new URL("jar:" + Utilities.toURI(jar).toURL() + "!/"));
return Collections.singletonList(res);
} catch (MalformedURLException ex) {
return Collections.emptyList();
}
}
@Override
public SuiteSources owner() {
return SuiteSources.this;
}
}
private static class ImmutableResult implements SourceForBinaryQueryImplementation2.Result {
private final FileObject[] roots;
ImmutableResult(FileObject... candidates) {
this(Arrays.asList(candidates));
}
ImmutableResult(Iterable<FileObject> all) {
int cnt = 0;
Iterator<FileObject> it = all.iterator();
while (it.hasNext()) {
if (it.next() != null) {
cnt++;
}
}
it = all.iterator();
roots = new FileObject[cnt];
for (int at = 0; at < cnt;) {
FileObject c = it.next();
if (c != null) {
roots[at++] = c;
}
}
}
@Override
public boolean preferSources() {
return true;
}
@Override
public FileObject[] getRoots() {
return roots;
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void removeChangeListener(ChangeListener cl) {
}
}
}