diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java index 82edd8c72..381ab721e 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java @@ -65,7 +65,7 @@ public static boolean isQuarkusExtensionWithDeploymentArtifact(Library library) if (library != null) { VirtualFile[] files = library.getFiles(OrderRootType.CLASSES); - for(int i=0; !result && i < files.length;++i) { + for (int i = 0; !result && i < files.length; ++i) { if (files[i].isDirectory()) { result = ToolDelegate.getDeploymentJarId(VfsUtilCore.virtualToIoFile(files[i])) != null; } @@ -77,7 +77,7 @@ public static boolean isQuarkusExtensionWithDeploymentArtifact(Library library) /** * Check if the Quarkus library needs to be recomputed and update it if required. * - * @param module the module to check + * @param module the module to check * @param progressIndicator */ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progressIndicator) { @@ -95,20 +95,28 @@ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progres Integer actualHash = computeHash(module); var qlib = OrderEntryUtil.findLibraryOrderEntry(ModuleRootManager.getInstance(module), QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); if (qlib == null || (actualHash != null && !actualHash.equals(previousHash)) || - !QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_VERSION.equals(component.getVersion())){ + !QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_VERSION.equals(component.getVersion())) { ModuleRootModificationUtil.updateModel(module, model -> { LibraryTable table = model.getModuleLibraryTable(); Library library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); while (library != null) { table.removeLibrary(library); - TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "removeLibrary"); + try { + TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "removeLibrary"); + } catch (Exception e) { + + } library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); } progressIndicator.checkCanceled(); progressIndicator.setText("Collecting Quarkus deployment dependencies..."); List[] files = toolDelegate.getDeploymentFiles(module, progressIndicator); LOGGER.info("Adding library to " + module.getName() + " previousHash=" + previousHash + " newHash=" + actualHash); - TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "addLibrary").send(); + try { + TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "addLibrary").send(); + } catch (Exception e) { + + } addLibrary(model, files, module); }); component.setHash(actualHash); @@ -120,7 +128,7 @@ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progres } private static void addLibrary(ModifiableRootModel model, List[] files, Module module) { - LibraryEx library = (LibraryEx)model.getModuleLibraryTable().createLibrary(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); + LibraryEx library = (LibraryEx) model.getModuleLibraryTable().createLibrary(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME); LibraryEx.ModifiableModelEx libraryModel = library.getModifiableModel(); for (VirtualFile rootFile : files[ToolDelegate.BINARY]) { @@ -145,14 +153,14 @@ private static Integer computeHash(Module module) { @Override public Set visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEntry, Set value) { if (!isQuarkusDeploymentLibrary(libraryOrderEntry) && isQuarkusExtensionWithDeploymentArtifact(libraryOrderEntry.getLibrary())) { - for(VirtualFile file : libraryOrderEntry.getFiles(OrderRootType.CLASSES)) { + for (VirtualFile file : libraryOrderEntry.getFiles(OrderRootType.CLASSES)) { value.add(file.getPath()); } } return value; } }, new HashSet<>()); - return files.isEmpty()?null:files.hashCode(); + return files.isEmpty() ? null : files.hashCode(); } /** @@ -174,7 +182,7 @@ public Boolean visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEnt } public static boolean isQuarkusLibrary(@NotNull LibraryOrderEntry libraryOrderEntry) { - return libraryOrderEntry.getLibraryName() != null && + return libraryOrderEntry.getLibraryName() != null && libraryOrderEntry.getLibraryName().contains(QuarkusConstants.QUARKUS_CORE_PREFIX); } @@ -204,9 +212,9 @@ public static boolean checkQuarkusVersion(Module module, Predicate pred .findFirst(); if (quarkusCoreJar.isPresent()) { Matcher quarkusCoreArtifactMatcher = QUARKUS_CORE_PATTERN.matcher(quarkusCoreJar.get().getName()); - if(quarkusCoreArtifactMatcher.matches()) { + if (quarkusCoreArtifactMatcher.matches()) { String quarkusVersion = quarkusCoreArtifactMatcher.group(1); - LOGGER.debug("Detected Quarkus version = " + quarkusVersion); + LOGGER.debug("Detected Quarkus version = " + quarkusVersion); Matcher quarkusVersionMatcher = QUARKUS_STANDARD_VERSIONING.matcher(quarkusVersion); return predicate.test(quarkusVersionMatcher); } else { @@ -219,7 +227,7 @@ public static boolean checkQuarkusVersion(Module module, Predicate pred public static Set getModulesURIs(Project project) { Set uris = new HashSet<>(); - for(Module module : ModuleManager.getInstance(project).getModules()) { + for (Module module : ModuleManager.getInstance(project).getModules()) { uris.add(PsiUtilsLSImpl.getProjectURI(module)); } return uris; diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusProjectService.java b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusProjectService.java index 97636622c..b8c5fac9a 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusProjectService.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusProjectService.java @@ -72,7 +72,7 @@ public QuarkusProjectService(Project project) { @Override public void moduleAdded(@NotNull Project project, @NotNull Module module) { - QuarkusModuleUtil.ensureQuarkusLibrary(module, new EmptyProgressIndicator()); + //QuarkusModuleUtil.ensureQuarkusLibrary(module, new EmptyProgressIndicator()); } public VirtualFile getSchema(Module module) { @@ -141,7 +141,7 @@ public void processModules(com.intellij.openapi.progress.ProgressIndicator progr if (!project.isDisposed()) { for (var module : ModuleManager.getInstance(project).getModules()) { LOGGER.info("Calling ensure from processModules"); - QuarkusModuleUtil.ensureQuarkusLibrary(module, progressIndicator); + // QuarkusModuleUtil.ensureQuarkusLibrary(module, progressIndicator); } } } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentModuleLoader.java b/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentModuleLoader.java new file mode 100644 index 000000000..3c0128ae8 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentModuleLoader.java @@ -0,0 +1,45 @@ +package com.redhat.devtools.intellij.quarkus.deployment; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.vfs.VirtualFile; +import com.redhat.devtools.intellij.lsp4ij.client.CoalesceByKey; +import com.redhat.devtools.intellij.lsp4ij.internal.PromiseToCompletableFuture; +import com.redhat.devtools.intellij.quarkus.tool.ToolDelegate; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil.isQuarkusModule; + +public class QuarkusDeploymentModuleLoader extends PromiseToCompletableFuture[]> { + + private static final Logger LOGGER = LoggerFactory.getLogger(QuarkusDeploymentModuleLoader.class); + + public QuarkusDeploymentModuleLoader(@NotNull Module module) { + super(progressIndicator -> { + return collectDeploymentFiles(module, progressIndicator); + }, "Quarkus deployment module loader", module.getProject(), module, new CoalesceByKey(QuarkusDeploymentModuleLoader.class.getName(), module.getName())); + init(); + } + + private static List[] collectDeploymentFiles(Module module, ProgressIndicator progressIndicator) { + if (module.isDisposed()) + return null; + LOGGER.info("Ensuring library to " + module.getName()); + long start = System.currentTimeMillis(); + ToolDelegate toolDelegate = ToolDelegate.getDelegate(module); + if (toolDelegate == null) { + return null; + } + LOGGER.info("Tool delegate found for " + module.getName()); + if (!isQuarkusModule(module)) { + return null; + } + LOGGER.info("isQuarkus module " + module.getName()); + return toolDelegate.getDeploymentFiles(module, progressIndicator); + } + +} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentSupport.java b/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentSupport.java new file mode 100644 index 000000000..4ec3933f1 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/deployment/QuarkusDeploymentSupport.java @@ -0,0 +1,79 @@ +package com.redhat.devtools.intellij.quarkus.deployment; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.impl.libraries.LibraryEx; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; +import com.redhat.devtools.intellij.quarkus.QuarkusConstants; +import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; +import com.redhat.devtools.intellij.quarkus.tool.ToolDelegate; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; + +public class QuarkusDeploymentSupport { + + + private static final Key> QUARKUS_DEPLOYMENT_LOADER_KEY = new Key<>(QuarkusDeploymentSupport.class.getName()); + + public static CompletableFuture updateClasspathWithQuarkusDeployment(Module module) { + CompletableFuture loader = module.getUserData(QUARKUS_DEPLOYMENT_LOADER_KEY); + if (isOutOfDated(loader)) { + return updateClasspathWithQuarkusDeploymentSync(module); + } + return loader; + } + + private static boolean isOutOfDated(CompletableFuture loader) { + return loader == null || loader.isCancelled() || loader.isCompletedExceptionally(); + } + + @NotNull + private synchronized static CompletableFuture updateClasspathWithQuarkusDeploymentSync(Module module) { + CompletableFuture loader = module.getUserData(QUARKUS_DEPLOYMENT_LOADER_KEY); + if (!isOutOfDated(loader)) { + return loader; + } + var project = module.getProject(); + final CompletableFuture future = new CompletableFuture<>(); + CompletableFuture.runAsync(() -> { + Runnable task = () -> ProgressManager.getInstance().run(new Task.Backgroundable(project, "Computing deployment jars...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + System.out.println("Computing deployment jars..."); + try { + long start = System.currentTimeMillis(); + QuarkusModuleUtil.ensureQuarkusLibrary(module, indicator); + long elapsed = System.currentTimeMillis() - start; + System.out.println("Ensured QuarkusLibrary in " + elapsed + " ms"); + future.complete(null); + } catch (CancellationException | ProcessCanceledException e) { + future.cancel(true); + } catch (Exception e) { + if (module != null) { + } + future.completeExceptionally(e); + } + } + }); + if (DumbService.getInstance(project).isDumb()) { + DumbService.getInstance(project).runWhenSmart(task); + } else { + task.run(); + } + }); + module.putUserData(QUARKUS_DEPLOYMENT_LOADER_KEY, future); + return future; + } + +} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java index 282cc2e35..b9c931460 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java @@ -33,6 +33,7 @@ import com.redhat.devtools.intellij.lsp4mp4ij.settings.MicroProfileInspectionsInfo; import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings; import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; +import com.redhat.devtools.intellij.quarkus.deployment.QuarkusDeploymentSupport; import org.eclipse.lsp4j.*; import org.eclipse.lsp4mp.commons.*; import org.eclipse.lsp4mp.commons.codeaction.CodeActionResolveData; @@ -41,6 +42,7 @@ import org.eclipse.lsp4mp.ls.api.MicroProfileLanguageServerAPI; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -144,11 +146,31 @@ private boolean isConfigSource(VirtualFile file) { @Override public CompletableFuture getProjectInfo(MicroProfileProjectInfoParams params) { + IPsiUtils utils = PsiUtilsLSImpl.getInstance(getProject()); + VirtualFile file = null; + try { + file = utils.findFile(params.getUri()); + } catch (IOException e) { + throw new RuntimeException(e); + } + Module module = utils.getModule(file); + if (module == null) { + throw new RuntimeException(); + } + CompletableFuture loader = QuarkusDeploymentSupport.updateClasspathWithQuarkusDeployment(module); + if (loader.isDone()) { + return internalGetProjectInfo(params); + } + return loader + .thenCompose(unused -> internalGetProjectInfo(params)); + } + + private CompletableFuture internalGetProjectInfo(MicroProfileProjectInfoParams params) { var coalesceBy = new CoalesceByKey("microprofile/projectInfo", params.getUri(), params.getScopes()); String filePath = getFilePath(params.getUri()); return runAsBackground("Computing MicroProfile properties for '" + filePath + "'.", monitor -> - PropertiesManager.getInstance().getMicroProfileProjectInfo(params, PsiUtilsLSImpl.getInstance(getProject()), monitor) - , coalesceBy); + PropertiesManager.getInstance().getMicroProfileProjectInfo(params, PsiUtilsLSImpl.getInstance(getProject()), monitor) + , coalesceBy); } @Override diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/maven/MavenToolDelegate.java b/src/main/java/com/redhat/devtools/intellij/quarkus/maven/MavenToolDelegate.java index d3b72a53e..7247f4aea 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/maven/MavenToolDelegate.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/maven/MavenToolDelegate.java @@ -168,7 +168,7 @@ private List ensureDownloaded(Module module, MavenProject mavenPr } } else { List infos = deploymentIds.stream().map(id -> new MavenArtifactInfo(id, "jar", classifier)).collect(Collectors.toList()); - result = serverWrapper.resolveTransitively(infos, mavenProject.getRemoteRepositories()); + result = serverWrapper.resolveArtifactTransitively(infos, mavenProject.getRemoteRepositories()).mavenResolvedArtifacts; } } catch (MavenProcessCanceledException | RuntimeException e) { LOGGER.warn(e.getLocalizedMessage(), e);