Skip to content

Commit 6844a67

Browse files
committed
Allow to update multiple projects at the same time
- Multiple project can be updated at the same time via 'java/projectConfigurationsUpdate' request. - Argument of this request is 'ProjectConfigurationsUpdateParam', which contains a list of 'TextDocumentIdentifier'. Signed-off-by: sheche <[email protected]>
1 parent 55f63b9 commit 6844a67

File tree

6 files changed

+215
-9
lines changed

6 files changed

+215
-9
lines changed

org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls.
5656
org.eclipse.jdt.ls.core.internal.text.correction;x-friends:="org.eclipse.jdt.ls.tests",
5757
org.eclipse.jdt.ls.internal.gradle.checksums;x-friends:="org.eclipse.jdt.ls.tests",
5858
org.eclipse.jdt.ls.core.internal.filesystem;x-friends:="org.eclipse.jdt.ls.tests",
59-
org.eclipse.lsp4j.proposed;x-friends:="org.eclipse.jdt.ls.tests"
59+
org.eclipse.lsp4j.proposed;x-friends:="org.eclipse.jdt.ls.tests",
60+
org.eclipse.lsp4j.extended;x-friends:="org.eclipse.jdt.ls.tests"
6061
Bundle-ClassPath: lib/jsoup-1.14.2.jar,
6162
lib/remark-1.2.0.jar,
6263
.

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
import org.eclipse.lsp4j.WillSaveTextDocumentParams;
138138
import org.eclipse.lsp4j.WorkspaceEdit;
139139
import org.eclipse.lsp4j.WorkspaceSymbolParams;
140+
import org.eclipse.lsp4j.extended.ProjectConfigurationsUpdateParam;
140141
import org.eclipse.lsp4j.jsonrpc.CompletableFutures;
141142
import org.eclipse.lsp4j.jsonrpc.messages.Either;
142143
import org.eclipse.lsp4j.jsonrpc.services.JsonDelegate;
@@ -843,6 +844,16 @@ public void projectConfigurationUpdate(TextDocumentIdentifier param) {
843844
handler.updateConfiguration(param);
844845
}
845846

847+
/* (non-Javadoc)
848+
* @see org.eclipse.jdt.ls.core.internal.JavaProtocolExtensions#projectConfigurationsUpdate(org.eclipse.lsp4j.extended.ProjectConfigurationsUpdateParam)
849+
*/
850+
@Override
851+
public void projectConfigurationsUpdate(ProjectConfigurationsUpdateParam param) {
852+
logInfo(">> java/projectConfigurationsUpdate");
853+
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
854+
handler.updateConfigurations(param.getIdentifiers());
855+
}
856+
846857
/* (non-Javadoc)
847858
* @see org.eclipse.jdt.ls.core.internal.JavaProtocolExtensions#buildWorkspace(boolean)
848859
*/

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ProjectConfigurationUpdateHandler.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2016-2017 Red Hat Inc. and others.
2+
* Copyright (c) 2016-2022 Red Hat Inc. and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -12,8 +12,17 @@
1212
*******************************************************************************/
1313
package org.eclipse.jdt.ls.core.internal.handlers;
1414

15+
import java.util.Arrays;
16+
import java.util.HashSet;
17+
import java.util.List;
18+
import java.util.Set;
19+
1520
import org.eclipse.core.resources.IFile;
21+
import org.eclipse.core.resources.IProject;
22+
import org.eclipse.core.resources.ResourcesPlugin;
23+
import org.eclipse.core.runtime.IPath;
1624
import org.eclipse.jdt.ls.core.internal.JDTUtils;
25+
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
1726
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
1827
import org.eclipse.lsp4j.TextDocumentIdentifier;
1928

@@ -25,17 +34,47 @@ public class ProjectConfigurationUpdateHandler {
2534

2635
private ProjectsManager projectManager;
2736

28-
ProjectConfigurationUpdateHandler(ProjectsManager projectManager) {
37+
public ProjectConfigurationUpdateHandler(ProjectsManager projectManager) {
2938
this.projectManager = projectManager;
3039
}
3140

41+
public void updateConfigurations(List<TextDocumentIdentifier> param) {
42+
Set<IProject> projects = new HashSet<>();
43+
for (TextDocumentIdentifier identifier : param) {
44+
IProject project = getProjectFromUri(identifier.getUri());
45+
if (project != null) {
46+
projects.add(project);
47+
continue;
48+
}
49+
IFile file = JDTUtils.findFile(identifier.getUri());
50+
if (file == null) {
51+
continue;
52+
}
53+
project = file.getProject();
54+
if (project != null) {
55+
projects.add(project);
56+
}
57+
}
58+
59+
for (IProject project : projects) {
60+
// most likely the handler is invoked intentionally by the user, that's why
61+
// we force the update despite no changes of in build descriptor being made
62+
projectManager.updateProject(project, true);
63+
}
64+
}
65+
3266
public void updateConfiguration(TextDocumentIdentifier param) {
33-
IFile file = JDTUtils.findFile(param.getUri());
34-
if (file == null) {
35-
return;
67+
updateConfigurations(Arrays.asList(param));
68+
}
69+
70+
private IProject getProjectFromUri(String uri) {
71+
IPath uriPath = ResourceUtils.canonicalFilePathFromURI(uri);
72+
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
73+
for (IProject project : projects) {
74+
if (project.getLocation().equals(uriPath)) {
75+
return project;
76+
}
3677
}
37-
// most likely the handler is invoked intentionally by the user, that's why
38-
// we force the update despite no changes of in build descriptor being made
39-
projectManager.updateProject(file.getProject(), true);
78+
return null;
4079
}
4180
}

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/lsp/JavaProtocolExtensions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.eclipse.lsp4j.SymbolInformation;
4343
import org.eclipse.lsp4j.TextDocumentIdentifier;
4444
import org.eclipse.lsp4j.WorkspaceEdit;
45+
import org.eclipse.lsp4j.extended.ProjectConfigurationsUpdateParam;
4546
import org.eclipse.lsp4j.jsonrpc.messages.Either;
4647
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
4748
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
@@ -66,6 +67,13 @@ public interface JavaProtocolExtensions {
6667
@JsonNotification
6768
void projectConfigurationUpdate(TextDocumentIdentifier documentUri);
6869

70+
/**
71+
* Request multiple project configurations update
72+
* @param documentUris the documents from which the project configuration will be updated
73+
*/
74+
@JsonNotification
75+
void projectConfigurationsUpdate(ProjectConfigurationsUpdateParam documentUris);
76+
6977
@JsonRequest
7078
CompletableFuture<BuildWorkspaceStatus> buildWorkspace(Either<Boolean, boolean[]> forceReBuild);
7179

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2022 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Microsoft Corporation - initial API and implementation
12+
*******************************************************************************/
13+
14+
package org.eclipse.lsp4j.extended;
15+
16+
import java.util.List;
17+
18+
import org.eclipse.lsp4j.TextDocumentIdentifier;
19+
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
20+
import org.eclipse.lsp4j.util.Preconditions;
21+
import org.eclipse.xtext.xbase.lib.Pure;
22+
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
23+
24+
@SuppressWarnings("all")
25+
public class ProjectConfigurationsUpdateParam {
26+
/**
27+
* The text document's identifiers.
28+
*/
29+
@NonNull
30+
private List<TextDocumentIdentifier> identifiers;
31+
32+
public ProjectConfigurationsUpdateParam() {
33+
}
34+
35+
public ProjectConfigurationsUpdateParam(@NonNull final List<TextDocumentIdentifier> identifiers) {
36+
this.identifiers = Preconditions.<List<TextDocumentIdentifier>>checkNotNull(identifiers, "identifiers");
37+
}
38+
39+
@Pure
40+
@NonNull
41+
public List<TextDocumentIdentifier> getIdentifiers() {
42+
return identifiers;
43+
}
44+
45+
public void setIdentifiers(@NonNull final List<TextDocumentIdentifier> identifiers) {
46+
this.identifiers = Preconditions.<List<TextDocumentIdentifier>>checkNotNull(identifiers, "identifiers");
47+
}
48+
49+
@Override
50+
@Pure
51+
public String toString() {
52+
ToStringBuilder b = new ToStringBuilder(this);
53+
b.add("identifiers", this.identifiers);
54+
return b.toString();
55+
}
56+
57+
@Override
58+
public int hashCode() {
59+
final int prime = 31;
60+
int result = 1;
61+
result = prime * result + ((identifiers == null) ? 0 : identifiers.hashCode());
62+
return result;
63+
}
64+
65+
@Override
66+
public boolean equals(Object obj) {
67+
if (this == obj)
68+
return true;
69+
if (obj == null)
70+
return false;
71+
if (getClass() != obj.getClass())
72+
return false;
73+
ProjectConfigurationsUpdateParam other = (ProjectConfigurationsUpdateParam) obj;
74+
if (identifiers == null) {
75+
if (other.identifiers != null)
76+
return false;
77+
} else if (!identifiers.equals(other.identifiers))
78+
return false;
79+
return true;
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2022 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Microsoft Corporation - initial API and implementation
12+
*******************************************************************************/
13+
14+
package org.eclipse.jdt.ls.core.internal.handlers;
15+
16+
import static org.mockito.ArgumentMatchers.any;
17+
import static org.mockito.ArgumentMatchers.anyBoolean;
18+
import static org.mockito.ArgumentMatchers.eq;
19+
import static org.mockito.Mockito.doNothing;
20+
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.times;
22+
import static org.mockito.Mockito.verify;
23+
import static org.mockito.Mockito.when;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
import org.eclipse.core.resources.IProject;
29+
import org.eclipse.jdt.ls.core.internal.WorkspaceHelper;
30+
import org.eclipse.jdt.ls.core.internal.managers.AbstractProjectsManagerBasedTest;
31+
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
32+
import org.eclipse.lsp4j.TextDocumentIdentifier;
33+
import org.eclipse.lsp4j.extended.ProjectConfigurationsUpdateParam;
34+
import org.junit.Test;
35+
36+
public class ProjectConfigurationUpdateHandlerTest extends AbstractProjectsManagerBasedTest {
37+
38+
@Test
39+
public void testUpdateConfiguration() throws Exception {
40+
importProjects("maven/multimodule");
41+
ProjectsManager pm = mock(ProjectsManager.class);
42+
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
43+
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
44+
IProject project = WorkspaceHelper.getProject("multimodule");
45+
handler.updateConfiguration(new TextDocumentIdentifier(project.getLocationURI().toString()));
46+
verify(pm, times(1)).updateProject(any(IProject.class), eq(true));
47+
}
48+
49+
@Test
50+
public void testUpdateConfigurations() throws Exception {
51+
importProjects("maven/multimodule");
52+
ProjectsManager pm = mock(ProjectsManager.class);
53+
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
54+
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
55+
List<TextDocumentIdentifier> list = new ArrayList<>();
56+
IProject project = WorkspaceHelper.getProject("module1");
57+
list.add(new TextDocumentIdentifier(project.getLocationURI().toString()));
58+
project = WorkspaceHelper.getProject("module2");
59+
list.add(new TextDocumentIdentifier(project.getLocationURI().toString()));
60+
61+
ProjectConfigurationsUpdateParam param = new ProjectConfigurationsUpdateParam(list);
62+
63+
handler.updateConfigurations(param.getIdentifiers());
64+
verify(pm, times(2)).updateProject(any(IProject.class), eq(true));
65+
}
66+
}

0 commit comments

Comments
 (0)