Send 'initial' classpath change events

Classpath events for all existing projects are sent when
a listener registers (in addition to events that are sent when
the classpath changes).
This commit is contained in:
Kris De Volder
2018-03-16 14:29:27 -07:00
parent e16cb6a9c9
commit 9473dfd75a
4 changed files with 73 additions and 52 deletions

View File

@@ -67,11 +67,6 @@ public class ClasspathListenerManager {
return "done";
}));
// 2. call the client to ask it to call that callback
CompletableFuture<Object> future1 = server.getClient().addClasspathListener(
new ClasspathListenerParams(callbackCommandId)
);
// 2. register the callback command with the client
String registrationId = UUID.randomUUID().toString();
RegistrationParams params = new RegistrationParams(ImmutableList.of(
@@ -80,19 +75,20 @@ public class ClasspathListenerManager {
ImmutableMap.of("commands", ImmutableList.of(callbackCommandId))
)
));
CompletableFuture<Void> future2 = server.getClient().registerCapability(params);
server.getClient().registerCapability(params).join();
// Wait for async work
future1.join();
future2.join();
// 3. call the client to ask it to call that callback
server.getClient().addClasspathListener(
new ClasspathListenerParams(callbackCommandId)
).join();
// Cleanups:
return () -> {
unregisterCommand.dispose();
thenLog(log, this.server.getClient().removeClasspathListener(new ClasspathListenerParams(callbackCommandId)));
this.server.getClient().unregisterCapability(new UnregistrationParams(ImmutableList.of(
thenLog(log, this.server.getClient().unregisterCapability(new UnregistrationParams(ImmutableList.of(
new Unregistration(registrationId, WORKSPACE_EXECUTE_COMMAND)
)));
))));
};
}

View File

@@ -1,11 +1,25 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.jdt.ls.extension;
import static org.springframework.tooling.jdt.ls.extension.Logger.log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
import org.eclipse.jdt.ls.core.internal.JavaClientConnection;
@@ -15,58 +29,67 @@ import org.springframework.tooling.jdt.ls.extension.ClasspathListenerManager.Cla
@SuppressWarnings("restriction")
public class ClasspathListenerHandler implements IDelegateCommandHandler {
static class MyClasspathListener implements ClasspathListener {
private ClasspathListenerManager manager = null;
private List<String> subscribers = new ArrayList<>(1);
static class Subscribptions {
private static Map<String, ClasspathListenerManager> subscribers = null;
public synchronized void subscribe(String callbackCommandId) {
Logger.log("subscribing to classpath changes: " + callbackCommandId);
if (manager == null) {
this.manager = new ClasspathListenerManager(this);
if (subscribers==null) {
subscribers = new HashMap<>(1);
}
subscribers.add(callbackCommandId);
Logger.log("subsribers = " + subscribers);
}
@Override
public void classpathChanged(IJavaProject jp) {
log("Classpath changed " + jp.getElementName());
String project = jp.getProject().getLocationURI().toString();
boolean deleted = !jp.exists();
JavaClientConnection conn = JavaLanguageServerPlugin.getInstance().getClientConnection();
String projectName = jp.getElementName();
for (String callbackCommandId : subscribers) {
Classpath classpath = null;
if (!deleted) {
try {
classpath = ClasspathUtil.resolve(jp);
} catch (Exception e) {
Logger.log(e);
}
subscribers.computeIfAbsent(callbackCommandId, (cid) -> new ClasspathListenerManager(new ClasspathListener() {
@Override
public void classpathChanged(IJavaProject jp) {
sendNotification(callbackCommandId, jp);
}
}, true));
Logger.log("subsribers = " + subscribers.keySet());
}
private void sendNotification(String callbackCommandId, IJavaProject jp) {
//TODO: make one Job to accumulate all requested notification and work more efficiently by batching
// and avoiding multiple executions of duplicated requests.
new Job("SendClasspath notification") {
@Override
protected IStatus run(IProgressMonitor monitor) {
log("Classpath changed " + jp.getElementName());
String project = jp.getProject().getLocationURI().toString();
boolean deleted = !jp.exists();
JavaClientConnection conn = JavaLanguageServerPlugin.getInstance().getClientConnection();
String projectName = jp.getElementName();
Classpath classpath = null;
if (!deleted) {
try {
classpath = ClasspathUtil.resolve(jp);
} catch (Exception e) {
Logger.log(e);
}
}
conn.executeCommand(callbackCommandId, project, projectName, deleted, classpath);
return Status.OK_STATUS;
}
conn.executeCommand(callbackCommandId, project, projectName, deleted, classpath);
}
.schedule();
}
public synchronized void unsubscribe(String callbackCommandId) {
Logger.log("unsubscribing from classpath changes: " + callbackCommandId);
if (subscribers != null) {
subscribers.remove(callbackCommandId);
ClasspathListenerManager mgr = subscribers.remove(callbackCommandId);
if (mgr!=null) {
mgr.dispose();
}
if (subscribers.isEmpty()) {
subscribers = null;
if (manager != null) {
manager.dispose();
manager = null;
}
}
}
Logger.log("subsribers = " + subscribers);
Logger.log("subsribers = " + subscribers.keySet());
}
}
private static MyClasspathListener classpathListener = new MyClasspathListener();
private static Subscribptions subscribptions = new Subscribptions();
@Override
public Object executeCommand(String commandId, List<Object> arguments, IProgressMonitor monitor) throws Exception {
@@ -83,14 +106,14 @@ public class ClasspathListenerHandler implements IDelegateCommandHandler {
private Object removeClasspathListener(String callbackCommandId) {
log("ClasspathListenerHandler addClasspathListener " + callbackCommandId);
classpathListener.unsubscribe(callbackCommandId);
subscribptions.unsubscribe(callbackCommandId);
log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK");
return "ok";
}
private Object addClasspathListener(String callbackCommandId) {
log("ClasspathListenerHandler addClasspathListener " + callbackCommandId);
classpathListener.subscribe(callbackCommandId);
subscribptions.subscribe(callbackCommandId);
log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK");
return "ok";
}

View File

@@ -15,6 +15,8 @@ import java.util.List;
import org.eclipse.lsp4j.DocumentHighlight;
import org.eclipse.lsp4j.Position;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.handlers.HighlightProvider;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
@@ -24,6 +26,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
* @author Martin Lippert
*/
public class WebfluxRouteHighlightProdivder implements HighlightProvider {
private static final Logger log = LoggerFactory.getLogger(WebfluxRouteHighlightProdivder.class);
private final SpringIndexer springIndexer;
@@ -33,7 +37,7 @@ public class WebfluxRouteHighlightProdivder implements HighlightProvider {
@Override
public void provideHighlights(TextDocument document, Position position, List<DocumentHighlight> resultAccumulator) {
System.out.println(" PROVIDE HIGHLIGHTS: " + position.getLine() + "/" + position.getCharacter());
log.info("PROVIDE HIGHLIGHTS: {} / {}", position.getLine(), position.getCharacter());
this.springIndexer.getAdditonalInformation(document.getUri())
.stream()

View File

@@ -51,8 +51,6 @@ public class JdtLsProjectCache implements JavaProjectFinder, ProjectObserver {
@Override
public void changed(Event event) {
log.info("Classpath changed: "+ event.projectUri);
}
}))
);