package org.netbeans.gradle.project.query; import java.io.File; import javax.swing.event.ChangeListener; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.util.GradleFileUtils; import org.netbeans.gradle.project.util.LazyChangeSupport; import org.netbeans.gradle.project.util.NbFileUtils; import org.netbeans.gradle.project.util.NbFunction; import org.netbeans.gradle.project.util.NbSupplier; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; public final class GradleCacheByBinaryLookup { private static final FileObject[] NO_ROOTS = new FileObject[0]; private static final LazyChangeSupport CHANGES = LazyChangeSupport.createSwing(new EventSource()); private final String searchedPackaging; private final NbSupplier<File> gradleUserHomeProvider; private final NbFunction<FileObject, String> binaryToSearchedEntry; public GradleCacheByBinaryLookup( String searchedPackaging, NbSupplier<File> gradleUserHomeProvider, NbFunction<FileObject, String> binaryToSearchedEntry) { ExceptionHelper.checkNotNullArgument(searchedPackaging, "searchedPackaging"); ExceptionHelper.checkNotNullArgument(gradleUserHomeProvider, "gradleUserHomeProvider"); ExceptionHelper.checkNotNullArgument(binaryToSearchedEntry, "binaryToSearchedEntry"); this.searchedPackaging = searchedPackaging; this.gradleUserHomeProvider = gradleUserHomeProvider; this.binaryToSearchedEntry = binaryToSearchedEntry; } public static void notifyCacheChange() { CHANGES.fireChange(); } public SourceForBinaryQueryImplementation2.Result tryFindEntryByBinary(File binaryRoot) { File gradleUserHome = gradleUserHomeProvider.get(); if (gradleUserHome == null) { return null; } final FileObject binaryRootObj = FileUtil.toFileObject(binaryRoot); if (binaryRootObj == null) { return null; } FileObject cacheHome = FileUtil.toFileObject(gradleUserHome); if (cacheHome == null || !FileUtil.isParentOf(cacheHome, binaryRootObj)) { return null; } FileObject hashDir = binaryRootObj.getParent(); if (hashDir == null) { return null; } FileObject binDir = hashDir.getParent(); if (binDir == null) { return null; } String sourceFileName = binaryToSearchedEntry.apply(binaryRootObj); if (GradleFileUtils.isKnownBinaryDirName(binDir.getNameExt())) { final FileObject artifactRoot = binDir.getParent(); if (artifactRoot == null) { return null; } return new OldFormatCacheResult(artifactRoot, searchedPackaging, sourceFileName); } return new NewFormatCacheResult(binDir, sourceFileName); } private static final class EventSource implements SourceForBinaryQueryImplementation2.Result, LazyChangeSupport.Source { private volatile LazyChangeSupport changes; @Override public void init(LazyChangeSupport changes) { assert changes != null; this.changes = changes; } @Override public boolean preferSources() { return false; } @Override public FileObject[] getRoots() { return NO_ROOTS; } @Override public void addChangeListener(ChangeListener l) { changes.addChangeListener(l); } @Override public void removeChangeListener(ChangeListener l) { changes.removeChangeListener(l); } } private static class NewFormatCacheResult implements SourceForBinaryQueryImplementation2.Result { private final FileObject artifactRoot; private final String sourceFileName; public NewFormatCacheResult(FileObject artifactRoot, String sourceFileName) { this.artifactRoot = artifactRoot; this.sourceFileName = sourceFileName; } @Override public boolean preferSources() { return false; } @Override public FileObject[] getRoots() { // The cache directory of Gradle looks like this: // // ...... \\HASH_OF_SOURCE\\binary-sources.XXX // ...... \\HASH_OF_BINARY\\binary.XXX FileObject srcFile = NbFileUtils.getFileFromASubDir(artifactRoot, sourceFileName); return srcFile != null ? new FileObject[]{srcFile} : NO_ROOTS; } @Override public void addChangeListener(ChangeListener l) { CHANGES.addChangeListener(l); } @Override public void removeChangeListener(ChangeListener l) { CHANGES.removeChangeListener(l); } } private static class OldFormatCacheResult implements SourceForBinaryQueryImplementation2.Result { private final FileObject artifactRoot; private final String searchedPackaging; private final String searchedFileName; public OldFormatCacheResult(FileObject artifactRoot, String searchedPackaging, String searchedFileName) { this.artifactRoot = artifactRoot; this.searchedPackaging = searchedPackaging; this.searchedFileName = searchedFileName; } @Override public boolean preferSources() { return false; } @Override public FileObject[] getRoots() { // The cache directory of Gradle looks like this: // // ...... \\source\\HASH_OF_SOURCE\\binary-sources.jar // ...... \\packaging type\\HASH_OF_BINARY\\binary.jar FileObject searchedDir = artifactRoot.getFileObject(searchedPackaging); if (searchedDir == null) { return NO_ROOTS; } FileObject searchedFile = NbFileUtils.getFileFromASubDir(searchedDir, searchedFileName); return searchedFile != null ? new FileObject[]{searchedFile} : NO_ROOTS; } @Override public void addChangeListener(ChangeListener l) { CHANGES.addChangeListener(l); } @Override public void removeChangeListener(ChangeListener l) { CHANGES.removeChangeListener(l); } } }