diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaLanguageServerPlugin.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaLanguageServerPlugin.java index 87af954b71..aa0e4db68f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaLanguageServerPlugin.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaLanguageServerPlugin.java @@ -279,6 +279,7 @@ private void startConnection() throws IOException { Launcher launcher; ExecutorService executorService = Executors.newCachedThreadPool(); protocol = new JDTLanguageServer(projectsManager, preferenceManager); + Function wrapper = getWrapper(); if (JDTEnvironmentUtils.inSocketStreamDebugMode()) { String host = JDTEnvironmentUtils.getClientHost(); Integer port = JDTEnvironmentUtils.getClientPort(); @@ -288,8 +289,7 @@ private void startConnection() throws IOException { AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); InputStream in = Channels.newInputStream(socketChannel); OutputStream out = Channels.newOutputStream(socketChannel); - Function messageConsumer = it -> it; - launcher = Launcher.createIoLauncher(protocol, JavaLanguageClient.class, in, out, executorService, messageConsumer); + launcher = Launcher.createIoLauncher(protocol, JavaLanguageClient.class, in, out, executorService, wrapper); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Error when opening a socket channel at " + host + ":" + port + ".", e); } @@ -297,18 +297,31 @@ private void startConnection() throws IOException { ConnectionStreamFactory connectionFactory = new ConnectionStreamFactory(); InputStream in = connectionFactory.getInputStream(); OutputStream out = connectionFactory.getOutputStream(); - Function wrapper; - if ("false".equals(System.getProperty("watchParentProcess"))) { - wrapper = it -> it; - } else { - wrapper = new ParentProcessWatcher(this.languageServer); - } launcher = Launcher.createLauncher(protocol, JavaLanguageClient.class, in, out, executorService, wrapper); } protocol.connectClient(launcher.getRemoteProxy()); launcher.startListening(); } + private Function getWrapper() { + Function wrapper; + int pollDelaySecs = ParentProcessWatcher.POLL_DELAY_SECS; + String watchParentProcess = System.getProperty("watchParentProcess"); + if (watchParentProcess != null) { + try { + pollDelaySecs = Integer.parseInt(watchParentProcess); + } catch (Exception e) { + logException(e.getMessage(), e); + } + } + if (pollDelaySecs <= 0) { + wrapper = it -> it; + } else { + wrapper = new ParentProcessWatcher(this.languageServer, pollDelaySecs); + } + return wrapper; + } + /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) @@ -377,18 +390,18 @@ static void startLanguageServer(LanguageServer newLanguageServer) throws IOExcep * @return */ public static ProjectsManager getProjectsManager() { - return pluginInstance.projectsManager; + return pluginInstance == null ? null : pluginInstance.projectsManager; } public static DigestStore getDigestStore() { - return pluginInstance.digestStore; + return pluginInstance == null ? null : pluginInstance.digestStore; } /** * @return */ public static ContentProviderManager getContentProviderManager() { - return pluginInstance.contentProviderManager; + return pluginInstance == null ? null : pluginInstance.contentProviderManager; } /** @@ -478,4 +491,5 @@ public static void setPreferencesManager(PreferenceManager preferenceManager) { pluginInstance.preferenceManager = preferenceManager; } } + } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ParentProcessWatcher.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ParentProcessWatcher.java index 659be13332..d489ad9b7f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ParentProcessWatcher.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ParentProcessWatcher.java @@ -18,6 +18,7 @@ import java.util.function.Function; import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; import org.eclipse.lsp4j.jsonrpc.MessageConsumer; import com.google.common.io.Closeables; @@ -30,16 +31,21 @@ public final class ParentProcessWatcher implements Runnable, Function task; private ScheduledExecutorService service; + private String command; public ParentProcessWatcher(LanguageServer server ) { + this(server, POLL_DELAY_SECS); + } + + public ParentProcessWatcher(LanguageServer server, int pollDelaySecs) { this.server = server; service = Executors.newScheduledThreadPool(1); - task = service.scheduleWithFixedDelay(this, POLL_DELAY_SECS, POLL_DELAY_SECS, TimeUnit.SECONDS); + task = service.scheduleWithFixedDelay(this, pollDelaySecs, pollDelaySecs, TimeUnit.SECONDS); } @Override @@ -47,6 +53,7 @@ public void run() { if (!parentProcessStillRunning()) { JavaLanguageServerPlugin.logInfo("Parent process stopped running, forcing server exit"); task.cancel(true); + ProjectsManager.saveWorkspace(); server.exit(); } } @@ -63,12 +70,7 @@ private boolean parentProcessStillRunning() { if (pid == 0 || lastActivityTime > (System.currentTimeMillis() - INACTIVITY_DELAY_SECS)) { return true; } - String command; - if (Platform.OS_WIN32.equals(Platform.getOS())) { - command = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\""; - } else { - command = "ps -p " + pid; - } + String command = getCommand(pid); Process process = null; boolean finished = false; try { @@ -113,6 +115,17 @@ private boolean parentProcessStillRunning() { } } + private String getCommand(long pid) { + if (command == null) { + if (Platform.OS_WIN32.equals(Platform.getOS())) { + command = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\""; + } else { + command = "ps -p " + pid; + } + } + return command; + } + @Override public MessageConsumer apply(final MessageConsumer consumer) { //inject our own consumer to refresh the timestamp diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java index acfdcb50ac..21aad95a7f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java @@ -30,6 +30,7 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.ls.core.internal.JSONUtility; import org.eclipse.jdt.ls.core.internal.JavaClientConnection; @@ -241,7 +242,6 @@ public IStatus runInWorkspace(IProgressMonitor monitor) { connection.sendStatus(ServiceStatus.Starting, "Init..."); SubMonitor subMonitor = SubMonitor.convert(monitor, 100); try { - projectsManager.setAutoBuilding(false); projectsManager.initializeProjects(roots, subMonitor); projectsManager.setAutoBuilding(preferenceManager.getPreferences().isAutobuildEnabled()); JavaLanguageServerPlugin.logInfo("Workspace initialized in " + (System.currentTimeMillis() - start) + "ms"); @@ -264,9 +264,33 @@ public boolean belongsTo(Object family) { } }; - job.setPriority(Job.BUILD); - job.setRule(ResourcesPlugin.getWorkspace().getRoot()); - job.schedule(); + Job refresh = new Job("Refreshing...") { + + @Override + protected IStatus run(IProgressMonitor monitor) { + IJobManager jobManager = Job.getJobManager(); + try { + jobManager.join(ResourcesPlugin.FAMILY_AUTO_REFRESH, monitor); + jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, monitor); + jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, monitor); + } catch (OperationCanceledException | InterruptedException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + job.setPriority(Job.BUILD); + job.setRule(ResourcesPlugin.getWorkspace().getRoot()); + job.schedule(); + return Status.OK_STATUS; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) + */ + @Override + public boolean belongsTo(Object family) { + return JAVA_LS_INITIALIZATION_JOBS.equals(family); + } + }; + refresh.schedule(); } private Map getInitializationOptions(InitializeParams params) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java index f922d51e55..984f31fa5b 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java @@ -236,14 +236,18 @@ public void initialized(InitializedParams params) { public IStatus run(IProgressMonitor monitor) { try { IJobManager jobManager = Job.getJobManager(); - jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, null); - jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, null); + jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, monitor); + jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, monitor); logInfo(">> build jobs finished"); + if (JavaLanguageServerPlugin.getInstance() == null) { + return Status.CANCEL_STATUS; + } workspaceDiagnosticsHandler = new WorkspaceDiagnosticsHandler(JDTLanguageServer.this.client, pm); workspaceDiagnosticsHandler.publishDiagnostics(monitor); workspaceDiagnosticsHandler.addResourceChangeListener(); pm.registerWatchers(); logInfo(">> watchers registered"); + ProjectsManager.saveWorkspace(); } catch (OperationCanceledException | InterruptedException | CoreException e) { logException(e.getMessage(), e); return Status.CANCEL_STATUS; @@ -313,26 +317,30 @@ private CodeActionOptions getCodeActionOptions() { public CompletableFuture shutdown() { logInfo(">> shutdown"); return computeAsync((monitor) -> { - try { - JavaRuntime.removeVMInstallChangedListener(jvmConfigurator); - if (workspaceDiagnosticsHandler != null) { - workspaceDiagnosticsHandler.removeResourceChangeListener(); - workspaceDiagnosticsHandler = null; - } - ResourcesPlugin.getWorkspace().save(true, monitor); - } catch (CoreException e) { - logException(e.getMessage(), e); - } + removeListeners(); + ProjectsManager.saveWorkspace(); return new Object(); }); } + private void removeListeners() { + if (jvmConfigurator != null) { + JavaRuntime.removeVMInstallChangedListener(jvmConfigurator); + jvmConfigurator = null; + } + if (workspaceDiagnosticsHandler != null) { + workspaceDiagnosticsHandler.removeResourceChangeListener(); + workspaceDiagnosticsHandler = null; + } + } + /* (non-Javadoc) * @see org.eclipse.lsp4j.services.LanguageServer#exit() */ @Override public void exit() { logInfo(">> exit"); + removeListeners(); JavaLanguageServerPlugin.getLanguageServer().exit(); Executors.newSingleThreadScheduledExecutor().schedule(() -> { logInfo("Forcing exit after 1 min."); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java index 6f8f46ff4d..d4759ca58c 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java @@ -22,7 +22,6 @@ import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; @@ -174,7 +173,6 @@ private void updateProjects(Collection projects, long lastWorkspaceSta while (iterator.hasNext()) { IProject project = iterator.next(); project.open(monitor); - project.refreshLocal(IResource.DEPTH_INFINITE, monitor); if (!needsMavenUpdate(project, lastWorkspaceStateSaved)) { iterator.remove(); } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java index 99084681f5..dd2235c97a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java @@ -657,4 +657,15 @@ public File findFile(String formatterUrl) { return null; } + public static void saveWorkspace() { + try { + JavaLanguageServerPlugin.logInfo("Saving workspace"); + long start = System.currentTimeMillis(); + ResourcesPlugin.getWorkspace().save(true, null); + JavaLanguageServerPlugin.logInfo("Workspace saved. Took " + (System.currentTimeMillis() - start) + " ms"); + } catch (CoreException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + } + }