From b3a61025a5643c1fe72850c5f970796397006ecc Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Fri, 11 May 2018 12:31:03 -0700 Subject: [PATCH] Fix NPE in STS4LanguageClient related to classpath infra Also improve test coverage around this breakage. And improve the debugability of the tests by improving how they log configure logger. --- .../commons/STS4LanguageClientImpl.java | 7 +- .../.settings/org.eclipse.jdt.ui.prefs | 59 +++++++++ .../META-INF/MANIFEST.MF | 3 +- .../test/ClasspathListenerHandlerTest.java | 25 ++-- .../tooling/jdt/ls/commons/Logger.java | 115 ++++++++++++++---- .../jdt/ls/commons/classpath/Classpath.java | 2 + .../classpath/ClasspathListenerManager.java | 22 ++-- .../ls/commons/classpath/ClasspathUtil.java | 6 +- .../ReusableClasspathListenerHandler.java | 51 ++++---- .../ls/commons/resources/ResourceUtils.java | 12 +- .../extension/ClasspathListenerHandler.java | 15 ++- .../target-platform.target | 61 +++++----- 12 files changed, 258 insertions(+), 120 deletions(-) create mode 100644 headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/.settings/org.eclipse.jdt.ui.prefs diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java index 6f952f589..48db9fcb3 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java @@ -41,6 +41,7 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.progress.UIJob; import org.eclipse.ui.texteditor.AbstractTextEditor; +import org.springframework.tooling.jdt.ls.commons.Logger; import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathListenerHandler; import com.google.common.collect.ImmutableList; @@ -49,8 +50,10 @@ import com.google.common.collect.ImmutableMap; @SuppressWarnings("restriction") public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4LanguageClient { - private static ReusableClasspathListenerHandler classpathService = new ReusableClasspathListenerHandler(new LSP4ECommandExecutor()); - + private static ReusableClasspathListenerHandler classpathService = new ReusableClasspathListenerHandler( + Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), + new LSP4ECommandExecutor() + ); public STS4LanguageClientImpl() { System.out.println("Instantiatin STS4LanguageClientImpl"); diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/.settings/org.eclipse.jdt.ui.prefs b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..c743e1c07 --- /dev/null +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,59 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=true +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/META-INF/MANIFEST.MF b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/META-INF/MANIFEST.MF index 21a8640d2..67e0bd272 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/META-INF/MANIFEST.MF +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/META-INF/MANIFEST.MF @@ -12,5 +12,6 @@ Require-Bundle: org.springframework.tooling.jdt.ls.commons, org.apache.commons.lang3, org.junit, org.apache.commons.io, - org.eclipse.swt + org.eclipse.swt, + com.google.guava;bundle-version="21.0.0" diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springframework/tooling/jdt/ls/commons/test/ClasspathListenerHandlerTest.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springframework/tooling/jdt/ls/commons/test/ClasspathListenerHandlerTest.java index 64ff86550..d58f71e5a 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springframework/tooling/jdt/ls/commons/test/ClasspathListenerHandlerTest.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springframework/tooling/jdt/ls/commons/test/ClasspathListenerHandlerTest.java @@ -43,6 +43,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.springframework.tooling.jdt.ls.commons.Logger; +import org.springframework.tooling.jdt.ls.commons.Logger.DefaultLogger; +import org.springframework.tooling.jdt.ls.commons.Logger.TestLogger; import org.springframework.tooling.jdt.ls.commons.classpath.Classpath; import org.springframework.tooling.jdt.ls.commons.classpath.Classpath.CPE; import org.springframework.tooling.jdt.ls.commons.classpath.ClientCommandExecutor; @@ -50,12 +52,15 @@ import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathLis import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition; import org.springsource.ide.eclipse.commons.frameworks.test.util.Asserter; +import com.google.common.collect.ImmutableList; + import junit.framework.AssertionFailedError; public class ClasspathListenerHandlerTest { + private TestLogger logger = new TestLogger(); private MockClasspathCache classpaths = new MockClasspathCache(); - private ReusableClasspathListenerHandler service = new ReusableClasspathListenerHandler(classpaths); + private ReusableClasspathListenerHandler service = new ReusableClasspathListenerHandler(logger, classpaths); @Test public void classpathIsSentForExistingProject() throws Exception { String projectName = "classpath-test-simple-java-project"; @@ -82,7 +87,7 @@ public class ClasspathListenerHandlerTest { assertTrue(cp.getEntries().stream().filter(cpe -> Classpath.isSource(cpe)).count()==1); //has 1 source entry assertClasspath(cp, cp.getEntries().stream().filter(cpe -> Classpath.isBinary(cpe) && cpe.isSystem()).count()>=1); //has some system libraries }); - Logger.log("=== Deleteing project"); + logger.log("=== Deleteing project"); project.delete(false, true, null); ACondition.waitFor("Project classpath to disapear", Duration.ofSeconds(5), () -> { Info cp = classpaths.getFor(loc); @@ -96,7 +101,7 @@ public class ClasspathListenerHandlerTest { File loc = project.getLocation().toFile(); service.addClasspathListener(classpaths.commandId); - ACondition.waitFor("Project with classpath to appear", Duration.ofSeconds(50), () -> { + ACondition.waitFor("Project with classpath to appear", Duration.ofSeconds(5), () -> { Classpath cp = classpaths.getFor(loc).classpath; assertTrue(cp.getEntries().stream().filter(cpe -> Classpath.isSource(cpe)).count()==1); //has 1 source entry assertClasspath(cp, cp.getEntries().stream().filter(cpe -> Classpath.isBinary(cpe) && cpe.isSystem()).count()>=1); //has some system libraries @@ -105,7 +110,7 @@ public class ClasspathListenerHandlerTest { FileUtils.deleteQuietly(loc); safe(() -> project.refreshLocal(IResource.DEPTH_INFINITE, null)); - ACondition.waitFor("Project to disapear", Duration.ofSeconds(50), () -> { + ACondition.waitFor("Project to disapear", Duration.ofSeconds(5), () -> { Info cp = classpaths.getFor(loc); assertNull(cp); }); @@ -133,17 +138,18 @@ public class ClasspathListenerHandlerTest { Map classpaths = new HashMap<>(); @Override - public synchronized Object executeClientCommand(String id, Object... params) throws Exception { + public synchronized Object executeClientCommand(String id, Object... _params) throws Exception { if (id.equals(commandId)) { + ImmutableList params = ImmutableList.copyOf(_params); System.out.println("received: "+Arrays.asList(params)); - File projectLoc = new File(new URI((String) params[0])); - String name = (String) params[1]; - boolean deleted = (boolean) params[2]; + File projectLoc = new File(new URI((String) params.get(0))); + String name = (String) params.get(1); + boolean deleted = (boolean) params.get(2); if (deleted) { System.out.println("DELETING "+name); classpaths.remove(projectLoc); } else { - Classpath cp = (Classpath) params[3]; + Classpath cp = (Classpath) params.get(3); System.out.println("PUT "+name+" "+cp.getEntries().size()+" entries"); classpaths.put(projectLoc, new Info(name, cp)); } @@ -166,6 +172,7 @@ public class ClasspathListenerHandlerTest { classpaths.dispose(); deleteAllProjects(); assertTrue(service.hasNoActiveSubscriptions()); + logger.assertNoErrors(); } private static void assertClasspath(Classpath cp, boolean b) { diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/Logger.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/Logger.java index f856a2992..01def6302 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/Logger.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/Logger.java @@ -15,39 +15,102 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.Date; +import java.util.function.Supplier; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; + /** - * Poor man's logger which writes log output for jdt.ls extension into a predictable location. + * Poor man's logger with a defauly implementation writes log output for jdt.ls extension into a predictable location. */ -public class Logger { - - private static boolean USE_SYS_ERR = false; +public interface Logger { - private static PrintWriter printwriter; + public static Logger DEFAULT = new DefaultLogger(false); - static { - if (USE_SYS_ERR) { - printwriter = new PrintWriter(System.err); - } else { - File file = new File(System.getProperty("java.io.tmpdir")); - file = new File(file, "stsjdt.log"); - try { - printwriter = new PrintWriter(new FileOutputStream(file), true); - log("======== "+new Date()+" ======="); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + public static class DefaultLogger implements Logger { + private PrintWriter printwriter; + public DefaultLogger(boolean USE_SYS_ERR) { + if (USE_SYS_ERR) { + printwriter = new PrintWriter(System.err); + } else { + File file = new File(System.getProperty("java.io.tmpdir")); + file = new File(file, "stsjdt.log"); + try { + printwriter = new PrintWriter(new FileOutputStream(file), true); + log("======== "+new Date()+" ======="); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + @Override + public void log(String message) { + printwriter.println(message); + printwriter.flush(); + } + + @Override + public void log(Exception e) { + e.printStackTrace(printwriter); + } + } + + static Logger forEclipsePlugin(Supplier instance) { + return new Logger() { + + @Override + public void log(String message) { + try { + Plugin plugin = instance.get(); + plugin.getLog().log(new Status(IStatus.INFO, plugin.getBundle().getSymbolicName(), message)); + } catch (Exception ignore) { + //Eclipse state is fubar... send log message someplace else. + DEFAULT.log(message); + } + } + + @Override + public void log(Exception e) { + try { + Plugin plugin = instance.get(); + plugin.getLog().log(new Status(IStatus.ERROR, plugin.getBundle().getSymbolicName(), "", e)); + } catch (Exception ignore) { + //Eclipse state is fubar... send log message someplace else. + DEFAULT.log(e); + } + } + + }; + } + + + public static class TestLogger extends DefaultLogger { + + private Exception firstError; + + public TestLogger() { + super(true); + } + + @Override + public void log(Exception e) { + super.log(e); + if (firstError!=null) { + firstError = e; + } + } + + public void assertNoErrors() throws Exception { + if (firstError!=null) { + throw firstError; } } } - public static void log(String message) { - printwriter.println(message); - printwriter.flush(); - } - - public static void log(Exception e) { - e.printStackTrace(printwriter); - } - + void log(String message); + void log(Exception e); + } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java index 0f9c02b05..7537d8585 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java @@ -12,6 +12,7 @@ package org.springframework.tooling.jdt.ls.commons.classpath; import java.io.File; import java.net.URL; +import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.Assert; @@ -20,6 +21,7 @@ public class Classpath { public static final String ENTRY_KIND_SOURCE = "source"; public static final String ENTRY_KIND_BINARY = "binary"; + public static final Classpath EMPTY = new Classpath(Collections.emptyList()); private List entries; diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java index afe16b1f3..c40515140 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java @@ -40,7 +40,7 @@ public class ClasspathListenerManager { @Override public void elementChanged(ElementChangedEvent event) { - Logger.log("changeEvent = "+event); + logger.log("changeEvent = "+event); visit(event.getDelta()); } @@ -83,6 +83,7 @@ public class ClasspathListenerManager { private ClasspathListener listener; private MyListener myListener; + private final Logger logger; /** * @param initialEvent If true, events are fired immediately on all existing java @@ -90,31 +91,32 @@ public class ClasspathListenerManager { * This allows clients to become aware of all classpaths from the start and * continually monitor them for changes from that point onward. */ - public ClasspathListenerManager(ClasspathListener listener, boolean initialEvent) { - log("Setting up ClasspathListenerManager"); + public ClasspathListenerManager(Logger logger, ClasspathListener listener, boolean initialEvent) { + this.logger = logger; + logger.log("Setting up ClasspathListenerManager"); this.listener = listener; JavaCore.addElementChangedListener(myListener=new MyListener(), ElementChangedEvent.POST_CHANGE); if (initialEvent) { - log("Sending initial event for all projects ..."); + logger.log("Sending initial event for all projects ..."); for (IProject p : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { - log("project "+p.getName() +" ..." ); + logger.log("project "+p.getName() +" ..." ); try { if (p.isAccessible() && p.hasNature(JavaCore.NATURE_ID)) { IJavaProject jp = JavaCore.create(p); listener.classpathChanged(jp); } else { - log("project "+p.getName() +" SKIPPED" ); + logger.log("project "+p.getName() +" SKIPPED" ); } } catch (CoreException e) { - Logger.log(e); + logger.log(e); } } - log("Sending initial event for all projects DONE"); + logger.log("Sending initial event for all projects DONE"); } } - public ClasspathListenerManager(ClasspathListener listener) { - this(listener, false); + public ClasspathListenerManager(Logger logger, ClasspathListener listener) { + this(logger, listener, false); } public void dispose() { diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java index 53be67170..f6431d42d 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.springframework.tooling.jdt.ls.commons.classpath; -import static org.springframework.tooling.jdt.ls.commons.Logger.log; import static org.springframework.tooling.jdt.ls.commons.classpath.Classpath.ENTRY_KIND_BINARY; import static org.springframework.tooling.jdt.ls.commons.classpath.Classpath.ENTRY_KIND_SOURCE; @@ -27,6 +26,7 @@ import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.internal.core.JavaProject; +import org.springframework.tooling.jdt.ls.commons.Logger; import org.springframework.tooling.jdt.ls.commons.classpath.Classpath.CPE; public class ClasspathUtil { @@ -59,7 +59,7 @@ public class ClasspathUtil { return null; } - public static Classpath resolve(IJavaProject javaProject) throws Exception { + public static Classpath resolve(IJavaProject javaProject, Logger logger) throws Exception { //log("resolving classpath " + javaProject.getElementName() +" ..."); List cpEntries = new ArrayList<>(); @@ -106,7 +106,7 @@ public class ClasspathUtil { } } Classpath classpath = new Classpath(cpEntries); - log("classpath=" + classpath.getEntries().size() + " entries"); + logger.log("classpath=" + classpath.getEntries().size() + " entries"); return classpath; } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java index c7f2f2454..5cd3a0b21 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java @@ -10,14 +10,11 @@ *******************************************************************************/ package org.springframework.tooling.jdt.ls.commons.classpath; -import static org.springframework.tooling.jdt.ls.commons.Logger.log; - import java.io.File; import java.net.URI; import java.util.HashMap; import java.util.Map; -import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -31,11 +28,13 @@ import org.springframework.tooling.jdt.ls.commons.classpath.ClasspathListenerMan */ public class ReusableClasspathListenerHandler { - private ClientCommandExecutor conn; + private final ClientCommandExecutor conn; + private final Logger logger; - public ReusableClasspathListenerHandler(ClientCommandExecutor conn) { + public ReusableClasspathListenerHandler(Logger logger, ClientCommandExecutor conn) { this.conn = conn; - log("Instantiating ReusableClasspathListenerHandler"); + this.logger = logger; + logger.log("Instantiating ReusableClasspathListenerHandler"); } /** @@ -81,17 +80,17 @@ public class ReusableClasspathListenerHandler { private Map subscribers = null; public synchronized void subscribe(String callbackCommandId) { - Logger.log("subscribing to classpath changes: " + callbackCommandId); + logger.log("subscribing to classpath changes: " + callbackCommandId); if (subscribers==null) { subscribers = new HashMap<>(1); } - subscribers.computeIfAbsent(callbackCommandId, (cid) -> new ClasspathListenerManager(new ClasspathListener() { + subscribers.computeIfAbsent(callbackCommandId, (cid) -> new ClasspathListenerManager(logger, new ClasspathListener() { @Override public void classpathChanged(IJavaProject jp) { sendNotification(callbackCommandId, jp); } }, true)); - Logger.log("subsribers = " + subscribers.keySet()); + logger.log("subsribers = " + subscribers.keySet()); } private void sendNotification(String callbackCommandId, IJavaProject jp) { @@ -102,10 +101,10 @@ public class ReusableClasspathListenerHandler { protected IStatus run(IProgressMonitor monitor) { synchronized (projectLocations) { //Could use some Eclipse job rule. But its really a bit of a PITA to create the right one. try { - log("Preparing classpath changed notification " + jp.getElementName()); + logger.log("Preparing classpath changed notification " + jp.getElementName()); URI projectLoc = getProjectLocation(jp); if (projectLoc==null) { - Logger.log("Could not send event for project because no project location: "+jp.getElementName()); + logger.log("Could not send event for project because no project location: "+jp.getElementName()); } else { boolean exsits = projectExists(jp); boolean open = true; // WARNING: calling is jp.isOpen is unreliable and subject to race condition. After a POST_CHAGE project open event @@ -115,31 +114,31 @@ public class ReusableClasspathListenerHandler { // So we will just pretend / assume project is always open. If resolving classpath fails because it is not // open... so be it (there will be no classpath... this is expected for closed project, so that is fine). boolean deleted = !(exsits && open); - Logger.log("exists = "+exsits +" open = "+open +" => deleted = "+deleted); + logger.log("exists = "+exsits +" open = "+open +" => deleted = "+deleted); String projectName = jp.getElementName(); - Classpath classpath = null; + Classpath classpath = Classpath.EMPTY; if (deleted) { projectLocations.remove(projectName); } else { projectLocations.put(projectName, projectLoc); try { - classpath = ClasspathUtil.resolve(jp); + classpath = ClasspathUtil.resolve(jp, logger); } catch (Exception e) { - Logger.log(e); + logger.log(e); } } try { - Logger.log("executing callback "+callbackCommandId+" "+projectName+" "+deleted+" "+(classpath==null ? "" : classpath.getEntries().size())); + logger.log("executing callback "+callbackCommandId+" "+projectName+" "+deleted+" "+ classpath.getEntries().size()); Object r = conn.executeClientCommand(callbackCommandId, projectLoc.toString(), projectName, deleted, classpath); - Logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]"); + logger.log("executing callback "+callbackCommandId+" SUCCESS ["+r+"]"); } catch (Exception e) { - Logger.log("executing callback "+callbackCommandId+" FAILED"); - Logger.log(e); + logger.log("executing callback "+callbackCommandId+" FAILED"); + logger.log(e); } } } catch (Exception e) { - Logger.log(e); + logger.log(e); } return Status.OK_STATUS; } @@ -149,7 +148,7 @@ public class ReusableClasspathListenerHandler { } public synchronized void unsubscribe(String callbackCommandId) { - Logger.log("unsubscribing from classpath changes: " + callbackCommandId); + logger.log("unsubscribing from classpath changes: " + callbackCommandId); if (subscribers != null) { ClasspathListenerManager mgr = subscribers.remove(callbackCommandId); if (mgr!=null) { @@ -159,7 +158,7 @@ public class ReusableClasspathListenerHandler { subscribers = null; } } - Logger.log("subsribers = " + (subscribers == null ? "null" : subscribers.keySet())); + logger.log("subsribers = " + (subscribers == null ? "null" : subscribers.keySet())); } public boolean isEmpty() { @@ -170,16 +169,16 @@ public class ReusableClasspathListenerHandler { private Subscribptions subscribptions = new Subscribptions(); public Object removeClasspathListener(String callbackCommandId) { - log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId); + logger.log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId); subscribptions.unsubscribe(callbackCommandId); - log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId + " => OK"); + logger.log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId + " => OK"); return "ok"; } public Object addClasspathListener(String callbackCommandId) { - log("ClasspathListenerHandler addClasspathListener " + callbackCommandId); + logger.log("ClasspathListenerHandler addClasspathListener " + callbackCommandId); subscribptions.subscribe(callbackCommandId); - log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK"); + logger.log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK"); return "ok"; } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java index 1dc2e1206..9bcbd2c6d 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java @@ -34,22 +34,22 @@ public final class ResourceUtils { */ public static IJavaProject getJavaProject(URI resourceUri) throws Exception { IContainer[] containers = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(resourceUri); - log("containers=" + containers); +// log("containers=" + containers); if (containers.length > 0) { - log("containers.length=" + containers.length); +// log("containers.length=" + containers.length); Optional shortest = Arrays.stream(containers) .min((f1, f2) -> f1.getFullPath().segmentCount() - f2.getFullPath().segmentCount()); - log("shortest=" + shortest.isPresent()); +// log("shortest=" + shortest.isPresent()); if (shortest.isPresent()) { - log("shortest.fullpath=" + shortest.get().getFullPath()); +// log("shortest.fullpath=" + shortest.get().getFullPath()); IProject project = shortest.get().getProject(); - log("project=" + project.getName()); +// log("project=" + project.getName()); if (project.isAccessible() && project.hasNature(JavaCore.NATURE_ID)) { IJavaProject javaProject = JavaCore.create(project); - log("javaProject=" + javaProject.getElementName()); +// log("javaProject=" + javaProject.getElementName()); return javaProject; } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/ClasspathListenerHandler.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/ClasspathListenerHandler.java index eb43b3212..843789a2c 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/ClasspathListenerHandler.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/ClasspathListenerHandler.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.springframework.tooling.jdt.ls.extension; -import static org.springframework.tooling.jdt.ls.commons.Logger.log; - import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; @@ -25,18 +23,19 @@ import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathLis @SuppressWarnings("restriction") public class ClasspathListenerHandler implements IDelegateCommandHandler { + private static final Logger logger = Logger.DEFAULT; private static ReusableClasspathListenerHandler handlerImpl = checkSupported(); private static ReusableClasspathListenerHandler checkSupported() { try { JavaClientConnection.class.getMethod("executeClientCommand", String.class, Object[].class); - return new ReusableClasspathListenerHandler(new ClientCommandExecutor() { + return new ReusableClasspathListenerHandler(logger, new ClientCommandExecutor() { @Override public Object executeClientCommand(String id, Object... params) { return JavaLanguageServerPlugin.getInstance().getClientConnection().executeClientCommand(id, params); } }); } catch (Exception e) { - Logger.log(e); + logger.log(e); } return null; } @@ -46,7 +45,7 @@ public class ClasspathListenerHandler implements IDelegateCommandHandler { if (handlerImpl==null) { throw new UnsupportedOperationException("Command '"+commandId+"' not supported on older versions of JDT Language Server"); } - log("ClasspathListenerHandler executeCommand " + commandId + ", " + arguments); + logger.log("ClasspathListenerHandler executeCommand " + commandId + ", " + arguments); switch (commandId) { case "sts.java.addClasspathListener": return addClasspathListener((String) arguments.get(0)); @@ -58,14 +57,14 @@ public class ClasspathListenerHandler implements IDelegateCommandHandler { } private Object removeClasspathListener(String callbackCommandId) { - log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId); + logger.log("ClasspathListenerHandler removeClasspathListener " + callbackCommandId); return handlerImpl.removeClasspathListener(callbackCommandId); } private Object addClasspathListener(String callbackCommandId) { - log("ClasspathListenerHandler addClasspathListener " + callbackCommandId); + logger.log("ClasspathListenerHandler addClasspathListener " + callbackCommandId); handlerImpl.addClasspathListener(callbackCommandId); - log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK"); + logger.log("ClasspathListenerHandler addClasspathListener " + callbackCommandId + " => OK"); return "ok"; } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/target-platform.target b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/target-platform.target index c77a11c53..6379d953d 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/target-platform.target +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/target-platform.target @@ -1,16 +1,11 @@ - + - + - - - - - - + @@ -19,32 +14,40 @@ - - - - - + - - - + + + - - - - - - - - - - - + + + + + + + + + - - + + + + + + + + + + + + + + + +