From 3efcecf37954fee03b99eb41a51577124db66d9b Mon Sep 17 00:00:00 2001 From: Alexander Fedorov Date: Wed, 19 Aug 2020 20:01:30 +0300 Subject: [PATCH] Bug 558664 - Cquery integration should be extracted from LSP Core Part 6: Declare SupportedProtocolExtensions interface to access contributed LanguageProtocolExtension for a given language server. Extract ResolvePreferredServer class. Add ContributedProtocolExtensions OSGi component with tests. Change-Id: Iecb1fff5a29a559e3c9d8703cc7d8fa71bb18042 Signed-off-by: Alexander Fedorov --- .../ContributedProtocolExtensionsTest.java | 55 ++++++++++++++ .../core/tests/FakeProtocolExtension.java | 31 ++++++++ .../core/tests/FakeServerConfiguration.java | 43 +++++++++++ .../core/tests/ShowStatusTest.java | 2 +- .../META-INF/MANIFEST.MF | 3 +- ...nal.core.ContributedProtocolExtensions.xml | 8 ++ .../cdt/lsp/LanguageProtocolExtension.java | 34 +++++++++ .../cdt/lsp/SupportedLanguageServers.java | 2 +- .../cdt/lsp/SupportedProtocolExtensions.java | 29 ++++++++ .../lsp/core/CPPStreamConnectionProvider.java | 14 +--- .../core/ContributedProtocolExtensions.java | 74 +++++++++++++++++++ .../internal/core/ResolvePreferredServer.java | 31 ++++++++ 12 files changed, 312 insertions(+), 14 deletions(-) create mode 100644 lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ContributedProtocolExtensionsTest.java create mode 100644 lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeProtocolExtension.java create mode 100644 lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeServerConfiguration.java rename lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/{ => internal}/core/tests/ShowStatusTest.java (96%) create mode 100644 lsp/org.eclipse.cdt.lsp.core/OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions.xml create mode 100644 lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/LanguageProtocolExtension.java create mode 100644 lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedProtocolExtensions.java create mode 100644 lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ContributedProtocolExtensions.java create mode 100644 lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ResolvePreferredServer.java diff --git a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ContributedProtocolExtensionsTest.java b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ContributedProtocolExtensionsTest.java new file mode 100644 index 00000000000..3c5381b4663 --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ContributedProtocolExtensionsTest.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.core.tests; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.cdt.lsp.LanguageProtocolExtension; +import org.eclipse.cdt.lsp.LanguageServerConfiguration; +import org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions; +import org.junit.Test; + +public class ContributedProtocolExtensionsTest { + + private final LanguageServerConfiguration s1 = new FakeServerConfiguration("s1"); + private final LanguageServerConfiguration s2 = new FakeServerConfiguration("s2"); + private final LanguageServerConfiguration s3 = new FakeServerConfiguration("s3"); + private final LanguageProtocolExtension p1s1 = new FakeProtocolExtension("s1"); + private final LanguageProtocolExtension p2s1 = new FakeProtocolExtension("s1"); + private final LanguageProtocolExtension p3s2 = new FakeProtocolExtension("s2"); + + @Test + public void positive() { + ContributedProtocolExtensions extensions = new ContributedProtocolExtensions(); + assertEquals(0, extensions.all().size()); + assertEquals(0, extensions.applicable(s1).size()); + assertEquals(0, extensions.applicable(s2).size()); + assertEquals(0, extensions.applicable(s3).size()); + extensions.register(p1s1); + extensions.register(p2s1); + extensions.register(p3s2); + assertEquals(3, extensions.all().size()); + assertEquals(2, extensions.applicable(s1).size()); + assertEquals(1, extensions.applicable(s2).size()); + assertEquals(0, extensions.applicable(s3).size()); + extensions.unregister(p1s1); + extensions.unregister(p2s1); + extensions.unregister(p3s2); + assertEquals(0, extensions.all().size()); + assertEquals(0, extensions.applicable(s1).size()); + assertEquals(0, extensions.applicable(s2).size()); + assertEquals(0, extensions.applicable(s3).size()); + } + +} diff --git a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeProtocolExtension.java b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeProtocolExtension.java new file mode 100644 index 00000000000..35dae5bf75f --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeProtocolExtension.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.core.tests; + +import org.eclipse.cdt.lsp.LanguageProtocolExtension; + +public class FakeProtocolExtension implements LanguageProtocolExtension { + + private final String id; + + public FakeProtocolExtension(String id) { + this.id = id; + } + + @Override + public String targetIdentifier() { + return id; + } + +} diff --git a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeServerConfiguration.java b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeServerConfiguration.java new file mode 100644 index 00000000000..8fe839138d3 --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/FakeServerConfiguration.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.core.tests; + +import java.net.URI; + +import org.eclipse.cdt.lsp.LanguageServerConfiguration; + +public class FakeServerConfiguration implements LanguageServerConfiguration { + + private final String id; + + public FakeServerConfiguration(String id) { + this.id = id; + } + + @Override + public String identifier() { + return id; + } + + @Override + public String label() { + return id; + } + + @Override + public Object options(Object defaults, URI uri) { + return defaults; + } + +} diff --git a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/ShowStatusTest.java b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ShowStatusTest.java similarity index 96% rename from lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/ShowStatusTest.java rename to lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ShowStatusTest.java index cf9d15a0b4f..d3386d539e8 100644 --- a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/ShowStatusTest.java +++ b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/internal/core/tests/ShowStatusTest.java @@ -11,7 +11,7 @@ * Contributors: * Alexander Fedorov (ArSysOp) - initial API and implementation *******************************************************************************/ -package org.eclipse.cdt.lsp.core.tests; +package org.eclipse.cdt.lsp.internal.core.tests; import static org.junit.Assert.assertEquals; diff --git a/lsp/org.eclipse.cdt.lsp.core/META-INF/MANIFEST.MF b/lsp/org.eclipse.cdt.lsp.core/META-INF/MANIFEST.MF index f361e02d61c..1f10dcf4912 100644 --- a/lsp/org.eclipse.cdt.lsp.core/META-INF/MANIFEST.MF +++ b/lsp/org.eclipse.cdt.lsp.core/META-INF/MANIFEST.MF @@ -35,4 +35,5 @@ Bundle-Activator: org.eclipse.cdt.lsp.core.Activator Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedLanguageServers.xml, OSGI-INF/org.eclipse.cdt.internal.clangd.ClangdLanguageServer.xml, - OSGI-INF/org.eclipse.cdt.internal.cquery.CqueryLanguageServer.xml + OSGI-INF/org.eclipse.cdt.internal.cquery.CqueryLanguageServer.xml, + OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions.xml diff --git a/lsp/org.eclipse.cdt.lsp.core/OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions.xml b/lsp/org.eclipse.cdt.lsp.core/OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions.xml new file mode 100644 index 00000000000..7f69e40edea --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/OSGI-INF/org.eclipse.cdt.lsp.internal.core.ContributedProtocolExtensions.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/LanguageProtocolExtension.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/LanguageProtocolExtension.java new file mode 100644 index 00000000000..e3e23a6b98c --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/LanguageProtocolExtension.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp; + +import org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints; + +/** + * + * Declares the language protocol extension methods. + * + * @see ServiceEndpoints#getSupportedMethods(Class) + * + */ +public interface LanguageProtocolExtension { + + /** + * + * @return the identifier of the target language server + * @see LanguageServerConfiguration#identifier() + */ + String targetIdentifier(); + +} diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedLanguageServers.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedLanguageServers.java index 6ab396c2025..72f25e28f97 100644 --- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedLanguageServers.java +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedLanguageServers.java @@ -17,7 +17,7 @@ import java.util.Collection; /** * - * Provides access to configurations of supported language servers. + * Provides access to the configurations of supported language servers. * */ public interface SupportedLanguageServers { diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedProtocolExtensions.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedProtocolExtensions.java new file mode 100644 index 00000000000..95e55302c9a --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/SupportedProtocolExtensions.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp; + +import java.util.Collection; + +/** + * + * Provides access to the language protocol extensions. + * + */ +public interface SupportedProtocolExtensions { + + Collection all(); + + Collection applicable(LanguageServerConfiguration server); + +} diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/CPPStreamConnectionProvider.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/CPPStreamConnectionProvider.java index 64f08f82424..522fe7a9dc2 100644 --- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/CPPStreamConnectionProvider.java +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/CPPStreamConnectionProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017-2020 Ericsson and others. + * Copyright (c) 2017, 2020 Ericsson and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -25,14 +25,13 @@ import java.util.Arrays; import java.util.List; import org.eclipse.cdt.lsp.LanguageServerConfiguration; -import org.eclipse.cdt.lsp.SupportedLanguageServers; +import org.eclipse.cdt.lsp.internal.core.ResolvePreferredServer; import org.eclipse.cdt.utils.CommandLineUtil; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.ServiceCaller; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider; @@ -47,7 +46,7 @@ public class CPPStreamConnectionProvider extends ProcessStreamConnectionProvider private final LanguageServerConfiguration configuration; public CPPStreamConnectionProvider() throws UnsupportedOperationException { - configuration = configuration(); + configuration = new ResolvePreferredServer().apply(getClass()); File defaultLSLocation = getDefaultLSLocation(configuration.identifier()); if (defaultLSLocation != null) { store.setDefault(PreferenceConstants.P_SERVER_PATH, defaultLSLocation.getAbsolutePath()); @@ -67,13 +66,6 @@ public class CPPStreamConnectionProvider extends ProcessStreamConnectionProvider setCommands(commands); } - private LanguageServerConfiguration configuration() { - final LanguageServerConfiguration[] configs = new LanguageServerConfiguration[1]; - ServiceCaller.callOnce(CPPStreamConnectionProvider.class, SupportedLanguageServers.class, - x -> configs[0] = x.preferred()); - return configs[0]; - } - @Override public void stop() { super.stop(); diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ContributedProtocolExtensions.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ContributedProtocolExtensions.java new file mode 100644 index 00000000000..7131a66be21 --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ContributedProtocolExtensions.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.core; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.eclipse.cdt.lsp.LanguageProtocolExtension; +import org.eclipse.cdt.lsp.LanguageServerConfiguration; +import org.eclipse.cdt.lsp.SupportedProtocolExtensions; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; + +@Component +public final class ContributedProtocolExtensions implements SupportedProtocolExtensions { + + private final Map> extensions; + + public ContributedProtocolExtensions() { + extensions = new LinkedHashMap<>(); + } + + @Override + public Collection all() { + return extensions.values().stream()// + .flatMap(List::stream)// + .collect(Collectors.toList()); + } + + @Override + public Collection applicable(LanguageServerConfiguration server) { + return new ArrayList<>(extensions.getOrDefault(server.identifier(), Collections.emptyList())); + } + + @Reference(cardinality = ReferenceCardinality.MULTIPLE) + public void register(LanguageProtocolExtension extension) { + List list = extensions.computeIfAbsent(extension.targetIdentifier(), + x -> new ArrayList<>()); + if (!list.contains(extension)) { + list.add(extension); + } + } + + public void unregister(LanguageProtocolExtension extension) { + Optional> optional = Optional + .ofNullable(extensions.get(extension.targetIdentifier())); + if (optional.isPresent()) { + List list = optional.get(); + list.remove(extension); + if (list.isEmpty()) { + extensions.remove(extension.targetIdentifier()); + } + } + } + +} diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ResolvePreferredServer.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ResolvePreferredServer.java new file mode 100644 index 00000000000..90d0895d6f3 --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/core/ResolvePreferredServer.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020 ArSysOp and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Alexander Fedorov (ArSysOp) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.core; + +import java.util.function.Function; + +import org.eclipse.cdt.lsp.LanguageServerConfiguration; +import org.eclipse.cdt.lsp.SupportedLanguageServers; +import org.eclipse.core.runtime.ServiceCaller; + +public final class ResolvePreferredServer implements Function, LanguageServerConfiguration> { + + @Override + public LanguageServerConfiguration apply(Class caller) { + LanguageServerConfiguration[] configs = new LanguageServerConfiguration[1]; + ServiceCaller.callOnce(caller, SupportedLanguageServers.class, x -> configs[0] = x.preferred()); + return configs[0]; + } + +}