Skip to content

Commit 839c8af

Browse files
authored
Allow to update multiple projects at the same time (#2131)
- Multiple projects 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 d1779cd commit 839c8af

File tree

6 files changed

+222
-9
lines changed

6 files changed

+222
-9
lines changed

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

+2-1
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

+11
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

+53-8
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,53 @@ 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+
/**
42+
* Update the projects' configurations (build files).
43+
*
44+
* @param identifiers the identifiers which may point to the projects' paths or
45+
* files that belong to some projects in the workspace.
46+
*/
47+
public void updateConfigurations(List<TextDocumentIdentifier> identifiers) {
48+
Set<IProject> projects = new HashSet<>();
49+
for (TextDocumentIdentifier identifier : identifiers) {
50+
IProject project = getProjectFromUri(identifier.getUri());
51+
if (project != null) {
52+
projects.add(project);
53+
continue;
54+
}
55+
IFile file = JDTUtils.findFile(identifier.getUri());
56+
if (file == null) {
57+
continue;
58+
}
59+
project = file.getProject();
60+
if (project != null) {
61+
projects.add(project);
62+
}
63+
}
64+
65+
for (IProject project : projects) {
66+
// most likely the handler is invoked intentionally by the user, that's why
67+
// we force the update despite no changes of in build descriptor being made
68+
projectManager.updateProject(project, true);
69+
}
70+
}
71+
3272
public void updateConfiguration(TextDocumentIdentifier param) {
33-
IFile file = JDTUtils.findFile(param.getUri());
34-
if (file == null) {
35-
return;
73+
updateConfigurations(Arrays.asList(param));
74+
}
75+
76+
private IProject getProjectFromUri(String uri) {
77+
IPath uriPath = ResourceUtils.canonicalFilePathFromURI(uri);
78+
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
79+
for (IProject project : projects) {
80+
if (project.getLocation().equals(uriPath)) {
81+
return project;
82+
}
3683
}
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);
84+
return null;
4085
}
4186
}

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

+10
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;
@@ -61,11 +62,20 @@ public interface JavaProtocolExtensions {
6162

6263
/**
6364
* Request a project configuration update
65+
*
66+
* @deprecated Please use {@link #projectConfigurationsUpdate(TextDocumentIdentifier)}.
6467
* @param documentUri the document from which the project configuration will be updated
6568
*/
6669
@JsonNotification
6770
void projectConfigurationUpdate(TextDocumentIdentifier documentUri);
6871

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

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,65 @@
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.mock;
20+
import static org.mockito.Mockito.times;
21+
import static org.mockito.Mockito.verify;
22+
import static org.mockito.Mockito.when;
23+
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
27+
import org.eclipse.core.resources.IProject;
28+
import org.eclipse.jdt.ls.core.internal.WorkspaceHelper;
29+
import org.eclipse.jdt.ls.core.internal.managers.AbstractProjectsManagerBasedTest;
30+
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
31+
import org.eclipse.lsp4j.TextDocumentIdentifier;
32+
import org.eclipse.lsp4j.extended.ProjectConfigurationsUpdateParam;
33+
import org.junit.Test;
34+
35+
public class ProjectConfigurationUpdateHandlerTest extends AbstractProjectsManagerBasedTest {
36+
37+
@Test
38+
public void testUpdateConfiguration() throws Exception {
39+
importProjects("maven/multimodule");
40+
ProjectsManager pm = mock(ProjectsManager.class);
41+
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
42+
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
43+
IProject project = WorkspaceHelper.getProject("multimodule");
44+
handler.updateConfiguration(new TextDocumentIdentifier(project.getLocationURI().toString()));
45+
verify(pm, times(1)).updateProject(any(IProject.class), eq(true));
46+
}
47+
48+
@Test
49+
public void testUpdateConfigurations() throws Exception {
50+
importProjects("maven/multimodule");
51+
ProjectsManager pm = mock(ProjectsManager.class);
52+
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
53+
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
54+
List<TextDocumentIdentifier> list = new ArrayList<>();
55+
IProject project = WorkspaceHelper.getProject("module1");
56+
list.add(new TextDocumentIdentifier(project.getLocationURI().toString()));
57+
project = WorkspaceHelper.getProject("module2");
58+
list.add(new TextDocumentIdentifier(project.getLocationURI().toString()));
59+
60+
ProjectConfigurationsUpdateParam param = new ProjectConfigurationsUpdateParam(list);
61+
62+
handler.updateConfigurations(param.getIdentifiers());
63+
verify(pm, times(2)).updateProject(any(IProject.class), eq(true));
64+
}
65+
}

0 commit comments

Comments
 (0)