PT #167595632: Update CMs after Classpath sent off to LS (Experimental)

This commit is contained in:
BoykoAlex
2019-08-02 14:31:36 -04:00
parent 0776c10491
commit 45b8a2e1dc
3 changed files with 102 additions and 3 deletions

View File

@@ -17,10 +17,14 @@ import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -58,6 +62,10 @@ import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
@@ -358,6 +366,31 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
}
}
public STS4LanguageClientImpl() {
classpathService.addNotificationsSentCallback(projectNames -> {
List<IProject> projects = projectNames.stream().map(projectName -> ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)).filter(Objects::nonNull).collect(Collectors.toList());
for (IWorkbenchWindow ww : PlatformUI.getWorkbench().getWorkbenchWindows()) {
for (IWorkbenchPage page : ww.getPages()) {
for (IEditorReference editorRef : page.getEditorReferences()) {
IEditorPart editor = editorRef.getEditor(false);
if (editor != null) {
if (editor.getEditorInput() instanceof IFileEditorInput) {
IFile file = ((IFileEditorInput)editor.getEditorInput()).getFile();
if (file != null && projects.contains(file.getProject())) {
ITextViewer viewer = editor.getAdapter(ITextViewer.class);
if (viewer instanceof ISourceViewerExtension5) {
((ISourceViewerExtension5)viewer).updateCodeMinings();
}
}
}
}
}
}
}
});
}
@Override
public CompletableFuture<Object> addClasspathListener(ClasspathListenerParams params) {
return CompletableFuture.completedFuture(classpathService.addClasspathListener(params.getCallbackCommandId(), params.isBatched()));

View File

@@ -15,14 +15,22 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import javax.management.Notification;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.springframework.tooling.jdt.ls.commons.Logger;
@@ -32,10 +40,15 @@ import org.springframework.tooling.jdt.ls.commons.classpath.ClasspathListenerMan
* {@link ReusableClasspathListenerHandler} is an 'abstracted' version of the jdtls ClasspathListenerHandler.
*/
public class ReusableClasspathListenerHandler {
public interface NotificationSentCallback {
void sent(Collection<String> projectNames);
}
private final Logger logger;
private final ClientCommandExecutor conn;
private final Supplier<Comparator<IProject>> projectSorterFactory;
private final ListenerList<NotificationSentCallback> notificationsSentCallbacks;
public ReusableClasspathListenerHandler(Logger logger, ClientCommandExecutor conn) {
this(logger, conn, null);
@@ -45,13 +58,40 @@ public class ReusableClasspathListenerHandler {
this.logger = logger;
this.projectSorterFactory = projectSorterFactory;
this.conn = conn;
this.notificationsSentCallbacks = new ListenerList<>();
logger.log("Instantiating ReusableClasspathListenerHandler");
}
private class CallbackJob extends Job {
public CallbackJob() {
super("Classpath Notiifcation Post Processing");
setSystem(true);
}
private Set<String> projectNames = Collections.synchronizedSet(new HashSet<>());
@Override
protected IStatus run(IProgressMonitor monitor) {
if (!projectNames.isEmpty()) {
notificationsSentCallbacks.forEach(callback -> callback.sent(projectNames));
}
return Status.OK_STATUS;
}
void queueProjects(Collection<String> projectNames) {
this.projectNames.addAll(projectNames);
schedule();
}
}
class Subscriptions {
private Map<String, SendClasspathNotificationsJob> subscribers = null;
private ClasspathListenerManager classpathListener = null;
private CallbackJob callbackJob = new CallbackJob();
public synchronized void subscribe(String callbackCommandId, boolean isBatched) {
if (subscribers==null) {
@@ -72,7 +112,19 @@ public class ReusableClasspathListenerHandler {
}
});
subscribers.put(callbackCommandId, new SendClasspathNotificationsJob(logger, conn, callbackCommandId, isBatched));
final SendClasspathNotificationsJob job = new SendClasspathNotificationsJob(logger, conn, callbackCommandId, isBatched);
subscribers.put(callbackCommandId, job);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
List<String> projectNames = job.notificationsSentForProjects;
if (projectNames != null) {
callbackJob.queueProjects(projectNames);
}
}
});
logger.log("subsribers = " + subscribers);
sendInitialEvents(callbackCommandId);
}
@@ -167,4 +219,11 @@ public class ReusableClasspathListenerHandler {
return subscribptions.isEmpty();
}
public void addNotificationsSentCallback(NotificationSentCallback callback) {
notificationsSentCallbacks.add(callback);
}
public void removeNotificationsSentCallback(NotificationSentCallback callback) {
notificationsSentCallbacks.remove(callback);
}
}

View File

@@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@@ -39,6 +40,8 @@ public class SendClasspathNotificationsJob extends Job {
private final Logger logger;
private String callbackCommandId;
List<String> notificationsSentForProjects;
/**
* Used only if caller has requested 'batched' events. This buffer, accumulates messsages to be sent out all at once,
* rather than one by one.
@@ -103,6 +106,7 @@ public class SendClasspathNotificationsJob extends Job {
@Override
protected IStatus run(IProgressMonitor monitor) {
notificationsSentForProjects = null;
synchronized (projectLocations) { //Could use some Eclipse job rule. But its really a bit of a PITA to create the right one.
try {
// Try to see if classpath needs to be sent for the projects that have been
@@ -177,6 +181,7 @@ public class SendClasspathNotificationsJob extends Job {
try {
logger.log("executing callback "+callbackCommandId+" "+projectName+" "+deleted+" "+ classpath.getEntries().size());
Object r = conn.executeClientCommand(callbackCommandId, projectLoc.toString(), projectName, deleted, classpath);
notificationsSentForProjects = ImmutableList.of(projectName);
logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]");
} catch (Exception e) {
logger.log("executing callback "+callbackCommandId+" FAILED");
@@ -190,6 +195,8 @@ public class SendClasspathNotificationsJob extends Job {
try {
logger.log("executing callback "+callbackCommandId+" "+buffer.size()+" batched events");
Object r = conn.executeClientCommand(callbackCommandId, buffer.toArray(new Object[buffer.size()]));
notificationsSentForProjects = ImmutableList.copyOf(buffer.stream().filter(l -> l instanceof List)
.map(l -> (List<?>) l).map(l -> (String) l.get(1)).collect(Collectors.toList()));
logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]");
} catch (Exception e) {
logger.log("executing callback "+callbackCommandId+" FAILED");