package org.netbeans.gradle.project; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import javax.swing.SwingUtilities; import org.jtrim.concurrent.UpdateTaskExecutor; import org.jtrim.property.PropertySource; import org.jtrim.utils.ExceptionHelper; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.classpath.GlobalPathRegistry; import org.netbeans.gradle.project.properties.GradleLocationDef; import org.netbeans.gradle.project.properties.global.CommonGlobalSettings; import org.netbeans.gradle.project.query.GradleHomeClassPathProvider; import org.netbeans.gradle.project.util.NbTaskExecutors; import org.netbeans.spi.java.classpath.ClassPathFactory; import org.netbeans.spi.java.classpath.ClassPathImplementation; import org.netbeans.spi.java.classpath.PathResourceImplementation; import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.filesystems.FileObject; public final class GradleHomeRegistry { private static final UpdateTaskExecutor GRADLE_HOME_UPDATER = NbTaskExecutors.newDefaultUpdateExecutor(); private static final AtomicReference<GradleHomePaths> GRADLE_HOME_BINARIES; private static final AtomicBoolean REGISTERED_GLOBAL_PATH; private static final AtomicBoolean USING_GLOBAL_PATHS; private static final PropertyChangeSupport CHANGES; static { EventSource eventSource = new EventSource(); CHANGES = new PropertyChangeSupport(eventSource); eventSource.init(CHANGES); USING_GLOBAL_PATHS = new AtomicBoolean(false); REGISTERED_GLOBAL_PATH = new AtomicBoolean(false); GRADLE_HOME_BINARIES = new AtomicReference<>(new GradleHomePaths()); } private static void doRegisterGlobalClassPath() { ClassPath classPath = ClassPathFactory.createClassPath(new ClassPathImplementation() { @Override public List<PathResourceImplementation> getResources() { return GRADLE_HOME_BINARIES.get().getPaths(); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { CHANGES.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { CHANGES.removePropertyChangeListener(listener); } }); GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, new ClassPath[]{classPath}); } private static PropertySource<GradleLocationDef> gradleLocation() { return CommonGlobalSettings.getDefault().gradleLocation().getActiveSource(); } public static void requireGradlePaths() { if (USING_GLOBAL_PATHS.compareAndSet(false, true)) { gradleLocation().addChangeListener(new Runnable() { @Override public void run() { updateGradleHome(); } }); updateGradleHome(); } } private static void updateGradleHome() { FileObject gradleHome = CommonGlobalSettings.getDefault().tryGetGradleInstallation(); if (gradleHome != null) { setGradleHome(gradleHome); } } private static void setGradleHome(final FileObject gradleHome) { ExceptionHelper.checkNotNullArgument(gradleHome, "gradleHome"); GRADLE_HOME_UPDATER.execute(new Runnable() { @Override public void run() { URL[] urls = GradleHomeClassPathProvider.getAllGradleLibs(gradleHome); if (urls.length == 0) { // Keep the previous classpaths if there are non found. return; } if (gradleHome.equals(GRADLE_HOME_BINARIES.get().getHomePath())) { return; } GRADLE_HOME_BINARIES.set(new GradleHomePaths(gradleHome, urls)); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { CHANGES.firePropertyChange(ClassPathImplementation.PROP_RESOURCES, null, null); } }); if (REGISTERED_GLOBAL_PATH.compareAndSet(false, true)) { doRegisterGlobalClassPath(); } } }); } private static class GradleHomePaths { private final FileObject homePath; private final List<PathResourceImplementation> paths; public GradleHomePaths() { this(null, new URL[0]); } public GradleHomePaths(FileObject homePath, URL[] urls) { ExceptionHelper.checkNotNullElements(urls, "urls"); this.homePath = homePath; List<PathResourceImplementation> resources = new ArrayList<>(urls.length); for (URL url: urls) { resources.add(ClassPathSupport.createResource(url)); } this.paths = Collections.unmodifiableList(resources); } public FileObject getHomePath() { return homePath; } public List<PathResourceImplementation> getPaths() { return paths; } } private static final class EventSource implements ClassPathImplementation { private volatile PropertyChangeSupport changes; public void init(PropertyChangeSupport changes) { assert changes != null; this.changes = changes; } @Override public List<PathResourceImplementation> getResources() { return Collections.emptyList(); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { changes.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { changes.removePropertyChangeListener(listener); } } }