From 783721b4f298b29f2f69f6d763623f52b32bf9b5 Mon Sep 17 00:00:00 2001 From: Christopher Hermann <79514265+Christopher-Hermann@users.noreply.github.com> Date: Wed, 3 May 2023 12:51:01 +0200 Subject: [PATCH] Use a custom ForkJoinWorkerThreadFactory in AsyncCompletionProposalPopup (#185) * Use a custom ForkJoinWorkerThreadFactory in AsyncCompletionProposalPopup CompletableFuture.supplyAsync() is using the defaultForkJoinWorkerThreadFactory. In case a SecurityManager is installed, using the defaultForkJoinWorkerThreadFactory would result in worker threads with no permissions, which leads to not content assist in the java editor. Use a custom ForkJoinWorkerThreadFactory implementation to work around this. See also: https://github.com/eclipse-platform/eclipse.platform/issues/294 https://github.com/eclipse-platform/eclipse.platform/pull/295 * Improve comment --- .../AsyncCompletionProposalPopup.java | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java index a5fe893241d..6babd4bf5b4 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java @@ -25,6 +25,8 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; @@ -42,6 +44,7 @@ import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.contentassist.IContentAssistSubjectControl; +import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; @@ -372,28 +375,40 @@ protected List>> buildCompletionFutu } List>> futures = new ArrayList<>(processors.size()); for (IContentAssistProcessor processor : processors) { - futures.add(CompletableFuture.supplyAsync(() -> { - AtomicReference> result= new AtomicReference<>(); - SafeRunner.run(() -> { - ICompletionProposal[] proposals= processor.computeCompletionProposals(fViewer, invocationOffset); - if (proposals == null) { - result.set(Collections.emptyList()); - } else { - result.set(Arrays.asList(proposals)); - } - }); - List proposals= result.get(); - if (proposals == null) { // an error occurred during computeCompletionProposal, - // possible improvement: give user feedback by returning an error "proposal" shown - // in completion popup and providing details - return Collections.emptyList(); - } - return proposals; - })); + // Use a custom ForkJoinWorkerThreadFactory, to prevent issues with a + // potential SecurityManager. Threads created by ForkJoinPool.commonPool(), + // which is used in CompletableFuture.supplyAsync(), get no permissions. + ForkJoinPool commonPool= new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism(), + pool -> new ForkJoinWorkerThread(pool) { + // anonymous subclass to access protected constructor + }, null, false); + futures.add(CompletableFuture.supplyAsync(() -> this.getCompletionProposals(processor, invocationOffset), commonPool)); } return futures; } + private List getCompletionProposals(IContentAssistProcessor processor, int invocationOffset) { + AtomicReference> result= new AtomicReference<>(); + SafeRunner.run(new SafeRunnable() { + @Override + public void run() throws Exception { + ICompletionProposal[] proposals= processor.computeCompletionProposals(fViewer, invocationOffset); + if (proposals == null) { + result.set(Collections.emptyList()); + } else { + result.set(Arrays.asList(proposals)); + } + } + }); + List proposals= result.get(); + if (proposals == null) { // an error occurred during computeCompletionProposal, + // possible improvement: give user feedback by returning an error "proposal" shown + // in completion popup and providing details + return Collections.emptyList(); + } + return proposals; + } + private String getTokenContentType(int invocationOffset) throws BadLocationException { if (fContentAssistSubjectControl != null) { IDocument document= fContentAssistSubjectControl.getDocument();