*/
package org.jetbrains.plugins.groovy.dsl;
+import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.ex.ApplicationUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
-import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
-import com.intellij.reference.SoftReference;
import com.intellij.util.ConcurrencyUtil;
-import com.intellij.util.ExceptionUtil;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ConcurrentMultiMap;
import com.intellij.util.indexing.*;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
+import com.intellij.util.io.URLUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.io.File;
-import java.io.IOException;
import java.util.*;
-import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
private static final MultiMap<String, LinkedBlockingQueue<Pair<VirtualFile, GroovyDslExecutor>>> filesInProcessing =
new ConcurrentMultiMap<String, LinkedBlockingQueue<Pair<VirtualFile, GroovyDslExecutor>>>();
- private static final ThreadPoolExecutor ourPool = new ThreadPoolExecutor(0, 4, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), ConcurrencyUtil.newNamedThreadFactory("Groovy DSL File Index Executor"));
+ private static final ThreadPoolExecutor ourPool = new ThreadPoolExecutor(4, 4, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), ConcurrencyUtil.newNamedThreadFactory("Groovy DSL File Index Executor"));
+
+ static {
+ ourPool.allowCoreThreadTimeOut(true);
+ }
private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor();
}
private static void clearScriptCache() {
- for (Project project : ProjectManager.getInstance().getOpenProjects()) {
- project.putUserData(SCRIPTS_CACHE, null);
- ((PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker()).incCounter();
- }
+ Application app = ApplicationManager.getApplication();
+ app.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ for (Project project : ProjectManager.getInstance().getOpenProjects()) {
+ project.putUserData(SCRIPTS_CACHE, null);
+ ((PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker()).incCounter();
+ }
+ }
+ }, app.getDisposed());
}
static void disableFile(final VirtualFile vfile, String error) {
return false;
}
- private static volatile SoftReference<List<Pair<File, GroovyDslExecutor>>> ourStandardScripts;
-
- @Nullable
- private static List<Pair<File, GroovyDslExecutor>> derefStandardScripts() {
- return SoftReference.dereference(ourStandardScripts);
- }
-
- @Nullable
- private static List<Pair<File, GroovyDslExecutor>> getStandardScripts() {
- List<Pair<File, GroovyDslExecutor>> result = derefStandardScripts();
- if (result != null) {
- return result;
- }
-
- final GroovyFrameworkConfigNotification[] extensions = GroovyFrameworkConfigNotification.EP_NAME.getExtensions();
- Callable<List<Pair<File, GroovyDslExecutor>>> action = new Callable<List<Pair<File, GroovyDslExecutor>>>() {
- @Override
- public List<Pair<File, GroovyDslExecutor>> call() throws Exception {
- if (GdslUtil.ourGdslStopped) {
- return null;
- }
-
- try {
- List<Pair<File, GroovyDslExecutor>> pairs = derefStandardScripts();
- if (pairs != null) {
- return pairs;
- }
-
- Set<Class> classes = new HashSet<Class>(ContainerUtil.map2Set(extensions, new Function<GroovyFrameworkConfigNotification, Class>() {
- @Override
- public Class fun(GroovyFrameworkConfigNotification notification) {
- return notification.getClass();
- }
- }));
- classes.add(GroovyFrameworkConfigNotification.class); // for default extension
-
- // perhaps a separate extension for that?
- Set<File> scriptFolders = new LinkedHashSet<File>();
- for (Class aClass : classes) {
- File jarPath = new File(PathUtil.getJarPathForClass(aClass));
- if (jarPath.isFile()) {
- jarPath = jarPath.getParentFile();
- }
- scriptFolders.add(new File(jarPath, "standardDsls"));
- }
+ private static final Key<CachedValue<List<GroovyDslScript>>> SCRIPTS_CACHE = Key.create("GdslScriptCache");
- List<Pair<File, GroovyDslExecutor>> executors = new ArrayList<Pair<File, GroovyDslExecutor>>();
- for (File file : scriptFolders) {
- if (file.exists()) {
- File[] children = file.listFiles();
- if (children != null) {
- for (File child : children) {
- final String fileName = child.getName();
- if (fileName.endsWith(".gdsl")) {
- try {
- final String text = new String(FileUtil.loadFileText(child));
- executors.add(Pair.create(child, new GroovyDslExecutor(text, fileName)));
- }
- catch (IOException e) {
- LOG.error("Error while parsing gdsl file " + fileName, e);
- }
- }
- }
- }
+ private static List<VirtualFile> getGdslFiles(final Project project) {
+ List<VirtualFile> result = ContainerUtil.newArrayList();
+
+ for (File file : getBundledScriptFolders()) {
+ if (file.exists()) {
+ File[] children = file.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ final String fileName = child.getName();
+ if (fileName.endsWith(".gdsl")) {
+ String path = FileUtil.toSystemIndependentName(child.getPath());
+ String url = VirtualFileManager.constructUrl(URLUtil.FILE_PROTOCOL, path);
+ ContainerUtil.addIfNotNull(result, VirtualFileManager.getInstance().refreshAndFindFileByUrl(url));
}
}
- //noinspection AssignmentToStaticFieldFromInstanceMethod
- ourStandardScripts = new SoftReference<List<Pair<File, GroovyDslExecutor>>>(executors);
- return executors;
- }
- catch (Throwable e) {
- //noinspection InstanceofCatchParameter
- if (e instanceof Error) {
- GdslUtil.stopGdsl();
- }
- LOG.error(e);
- return null;
}
}
- };
+ }
- try {
- if (ApplicationManager.getApplication().isDispatchThread()) {
- return action.call();
+ final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
+ final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
+
+ for (VirtualFile vfile : FileBasedIndex.getInstance().getContainingFiles(NAME, OUR_KEY, scope)) {
+ if (!vfile.isValid()) {
+ continue;
}
- return ApplicationUtil.runWithCheckCanceled(action, new EmptyProgressIndicator(), ourPool);
- }
- catch (Exception e) {
- ExceptionUtil.rethrowUnchecked(e);
- LOG.error(e);
- return null;
+ if (vfile.isDirectory() || !vfile.getName().endsWith(".gdsl")) {
+ LOG.error("Index returned non-gdsl file: " + vfile);
+ continue;
+ }
+ if (fileIndex.isInLibrarySource(vfile)) {
+ continue;
+ }
+ if (!fileIndex.isInLibraryClasses(vfile)) {
+ if (!fileIndex.isInSourceContent(vfile) || !isActivated(vfile)) {
+ continue;
+ }
+ }
+
+ result.add(vfile);
}
+ return result;
}
- private static final Key<CachedValue<List<GroovyDslScript>>> SCRIPTS_CACHE = Key.create("GdslScriptCache");
+ @NotNull
+ private static Set<File> getBundledScriptFolders() {
+ final GroovyFrameworkConfigNotification[] extensions = GroovyFrameworkConfigNotification.EP_NAME.getExtensions();
+ Set<Class> classes = new HashSet<Class>(ContainerUtil.map2Set(extensions, new Function<GroovyFrameworkConfigNotification, Class>() {
+ @Override
+ public Class fun(GroovyFrameworkConfigNotification notification) {
+ return notification.getClass();
+ }
+ }));
+ classes.add(GroovyFrameworkConfigNotification.class); // for default extension
+
+ // perhaps a separate extension for that?
+ Set<File> scriptFolders = new LinkedHashSet<File>();
+ for (Class aClass : classes) {
+ File jarPath = new File(PathUtil.getJarPathForClass(aClass));
+ if (jarPath.isFile()) {
+ jarPath = jarPath.getParentFile();
+ }
+ scriptFolders.add(new File(jarPath, "standardDsls"));
+ }
+ return scriptFolders;
+ }
private static List<GroovyDslScript> getDslScripts(final Project project) {
return CachedValuesManager.getManager(project).getCachedValue(project, SCRIPTS_CACHE, new CachedValueProvider<List<GroovyDslScript>>() {
List<GroovyDslScript> result = new ArrayList<GroovyDslScript>();
- List<Pair<File, GroovyDslExecutor>> standardScripts = getStandardScripts();
- if (standardScripts != null) {
- for (Pair<File, GroovyDslExecutor> pair : standardScripts) {
- result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath()));
- }
- }
-
final LinkedBlockingQueue<Pair<VirtualFile, GroovyDslExecutor>> queue =
new LinkedBlockingQueue<Pair<VirtualFile, GroovyDslExecutor>>();
- final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
- final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
- for (VirtualFile vfile : FileBasedIndex.getInstance().getContainingFiles(NAME, OUR_KEY, scope)) {
- if (!vfile.isValid()) {
- continue;
- }
- if (fileIndex.isInLibrarySource(vfile)) {
- continue;
- }
- if (!fileIndex.isInLibraryClasses(vfile)) {
- if (!fileIndex.isInSourceContent(vfile) || !isActivated(vfile)) {
- continue;
- }
- }
-
+ for (VirtualFile vfile : getGdslFiles(project)) {
final long stamp = vfile.getModificationStamp();
final GroovyDslExecutor cached = getCachedExecutor(vfile, stamp);
if (cached == null) {