diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java index b45c562cb..f09e56894 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java @@ -11,18 +11,25 @@ package org.springframework.ide.vscode.commons.boot.app.cli; import java.io.IOException; +import java.time.Duration; import java.util.Collection; import java.util.Map.Entry; import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.CollectorUtil; +import org.springframework.ide.vscode.commons.util.ExceptionUtil; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; +import reactor.core.scheduler.Schedulers; + /** * @author Martin Lippert */ @@ -30,11 +37,18 @@ public class LocalSpringBootApp extends AbstractSpringBootApp { private static final Logger logger = LoggerFactory.getLogger(LocalSpringBootApp.class); + private static AsyncRunner async = new AsyncRunner(Schedulers.elastic()); + private static T withTimeout(Callable doit) throws Exception { + return async.invoke(TIMEOUT, doit).get(); + } + private VirtualMachine vm; private VirtualMachineDescriptor vmd; private static final String LOCAL_CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; + private static final Duration TIMEOUT = Duration.ofMillis(1000); + private Boolean isSpringBootApp; private static LocalSpringBootAppCache cache = new LocalSpringBootAppCache(); @@ -111,7 +125,7 @@ public class LocalSpringBootApp extends AbstractSpringBootApp { return isSpringBootApp; } - private boolean isSpringBootAppSysprops() throws IOException { + private boolean isSpringBootAppSysprops() throws Exception { Properties sysprops = getSystemProperties(); return "org.springframework.boot.loader".equals(sysprops.getProperty("java.protocol.handler.pkgs")); } @@ -121,11 +135,11 @@ public class LocalSpringBootApp extends AbstractSpringBootApp { } @Override - public Properties getSystemProperties() throws IOException { - return this.vm.getSystemProperties(); + public Properties getSystemProperties() throws Exception { + return withTimeout(() -> vm.getSystemProperties()); } - public boolean containsSystemProperty(Object key) throws IOException { + public boolean containsSystemProperty(Object key) throws Exception { Properties props = getSystemProperties(); return props.containsKey(key); } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/jdt/ls/ClasspathListenerManager.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/jdt/ls/ClasspathListenerManager.java index 2575513b9..81ab755e3 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/jdt/ls/ClasspathListenerManager.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/jdt/ls/ClasspathListenerManager.java @@ -21,8 +21,8 @@ import org.eclipse.lsp4j.Unregistration; import org.eclipse.lsp4j.UnregistrationParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.languageserver.util.AsyncRunner; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index 663ceac03..4375bc31d 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.languageserver.util; -import static org.springframework.ide.vscode.commons.languageserver.util.AsyncRunner.thenLog; +import static org.springframework.ide.vscode.commons.util.AsyncRunner.thenLog; import java.net.URI; import java.nio.file.Paths; @@ -74,6 +74,7 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcil import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.CollectionUtil; import org.springframework.ide.vscode.commons.util.Log; @@ -143,7 +144,7 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA private Map commands = new HashMap<>(); - private AsyncRunner async = new AsyncRunner(); + private AsyncRunner async = new AsyncRunner(Schedulers.newSingle("SimpleLanguaserver main thread")); private ClasspathListenerManager classpathListenerManager; @Override diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index 9be363930..843e7a871 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -56,6 +56,7 @@ import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.TextDocumentService; import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix; import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.CollectorUtil; import org.springframework.ide.vscode.commons.util.ExceptionUtil; diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java index 9548c6295..739a59c9e 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java @@ -29,6 +29,7 @@ import org.eclipse.lsp4j.services.WorkspaceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.FileObserver; import org.springframework.ide.vscode.commons.util.Log; diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/AsyncRunner.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/AsyncRunner.java similarity index 82% rename from headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/AsyncRunner.java rename to headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/AsyncRunner.java index 776ee011a..b4a7ca748 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/AsyncRunner.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/AsyncRunner.java @@ -8,13 +8,13 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.languageserver.util; +package org.springframework.ide.vscode.commons.util; +import java.time.Duration; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; -import org.springframework.ide.vscode.commons.util.RunnableWithException; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; @@ -22,14 +22,24 @@ import reactor.core.scheduler.Schedulers; public class AsyncRunner { - private static Scheduler executor = Schedulers.newSingle("STS4 Thread"); + private Scheduler executor; // Used in test harness to wait for all pending request to finish. // We only need to remember the last request as requests are executed in order, so if // the last request is done, all requests are done private CompletableFuture lastRequest; - public AsyncRunner() { + public AsyncRunner(Scheduler scheduler) { + this.executor = scheduler; + } + + public synchronized CompletableFuture invoke(Duration timeout, Callable callable) { + CompletableFuture x = Mono.fromCallable(callable) + .timeout(timeout) + .subscribeOn(executor) + .toFuture(); + lastRequest = x; + return x; } public synchronized CompletableFuture invoke(Callable callable) {