Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Exposing a Language Server #4148

Merged
merged 2 commits into from Sep 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/.classpath
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
33 changes: 33 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/.project
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.smarthome.model.lsp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ds.core.builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
35 changes: 35 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/META-INF/MANIFEST.MF
@@ -0,0 +1,35 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse SmartHome Language Server
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-SymbolicName: org.eclipse.smarthome.model.lsp;singleton:=true
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.9.0.qualifier
Import-Package: com.google.inject,
javax.inject,
org.eclipse.emf.common.util,
org.eclipse.lsp4j.jsonrpc,
org.eclipse.lsp4j.launch,
org.eclipse.lsp4j.services,
org.eclipse.xtext,
org.eclipse.xtext.ide,
org.eclipse.xtext.ide.server,
org.eclipse.xtext.resource,
org.eclipse.xtext.resource.impl,
org.eclipse.xtext.util,
org.eclipse.xtext.workspace,
org.osgi.service.component.annotations;resolution:=optional,
org.slf4j
Require-Bundle: org.eclipse.smarthome.model.item.ide,
org.eclipse.smarthome.model.persistence.ide,
org.eclipse.smarthome.model.rule.ide,
org.eclipse.smarthome.model.script.ide,
org.eclipse.smarthome.model.sitemap.ide,
org.eclipse.smarthome.model.thing.ide,
org.eclipse.smarthome.model.item,
org.eclipse.smarthome.model.persistence,
org.eclipse.smarthome.model.rule,
org.eclipse.smarthome.model.script,
org.eclipse.smarthome.model.sitemap,
org.eclipse.smarthome.model.thing
Service-Component: OSGI-INF/*.xml
@@ -0,0 +1 @@
*.xml
28 changes: 28 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/about.html
@@ -0,0 +1,28 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>

<p>June 5, 2006</p>
<h3>License</h3>

<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>

<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>

</body>
</html>
@@ -0,0 +1,6 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
OSGI-INF/,\
about.html
22 changes: 22 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/pom.xml
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.smarthome.bundles</groupId>
<artifactId>model</artifactId>
<version>0.9.0-SNAPSHOT</version>
</parent>


<groupId>org.eclipse.smarthome.model</groupId>
<artifactId>org.eclipse.smarthome.model.lsp</artifactId>

<name>Eclipse SmartHome Language Server</name>
<packaging>eclipse-plugin</packaging>


</project>
@@ -0,0 +1,100 @@
/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.model.lsp.internal;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.launch.LSPLauncher;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.xtext.ide.server.LanguageServerImpl;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Guice;

/**
* A service component exposing a Language Server via sockets.
*
* @author Simon Kaufmann - initial contribution and API.
*
*/
@Component(immediate = true)
public class ModelServer {

private final Logger logger = LoggerFactory.getLogger(ModelServer.class);
private final int PORT = 5007;
private ServerSocket socket;

@Activate
public void activate() {
new Thread(() -> {
listen();
}, "Language Server").start();
}

@Deactivate
public void deactivate() {
try {
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
logger.error("Error shutting down the Language Server", e);
}
}

private void listen() {
try {
socket = new ServerSocket(PORT);
logger.info("Language Server started on port {}", PORT);
while (!socket.isClosed()) {
logger.debug("Going to wait for a client to connect");
try {
Socket client = socket.accept();
new Thread(() -> {
handleConnection(client);
}, "Client " + client.getRemoteSocketAddress()).start();
} catch (IOException e) {
logger.error("Error accepting the client connection", e);
}
}
} catch (IOException e) {
logger.error("Error starting the Language Server", e);
}
}

private void handleConnection(final Socket client) {
logger.debug("Client {} connected", client.getRemoteSocketAddress());
try {
LanguageServerImpl languageServer = Guice.createInjector(new RuntimeServerModule())
.getInstance(LanguageServerImpl.class);

Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(languageServer,
client.getInputStream(), client.getOutputStream());
languageServer.connect(launcher.getRemoteProxy());
Future<?> future = launcher.startListening();
future.get();
} catch (IOException e) {
logger.warn("Error communicating with LSP client {}", client.getRemoteSocketAddress());
} catch (InterruptedException e) {
// go on, let the thread finish
} catch (ExecutionException e) {
logger.error("Error running the Language Server", e);
}
logger.debug("Client {} disconnected", client.getRemoteSocketAddress());
}

}
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.model.lsp.internal;

import org.eclipse.smarthome.model.ide.ItemsIdeSetup;
import org.eclipse.smarthome.model.ide.SitemapIdeSetup;
import org.eclipse.smarthome.model.persistence.ide.PersistenceIdeSetup;
import org.eclipse.smarthome.model.rule.ide.RulesIdeSetup;
import org.eclipse.smarthome.model.script.ide.ScriptIdeSetup;
import org.eclipse.smarthome.model.thing.ide.ThingIdeSetup;
import org.eclipse.xtext.resource.FileExtensionProvider;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.IResourceServiceProvider.Registry;
import org.eclipse.xtext.resource.impl.ResourceServiceProviderRegistryImpl;

import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Singleton;

/**
* Provides the Xtext Registry for the Language Server.
*
* It just piggy-backs the static Resgitry instance that the runtime bundles are using anyway.
*
* @author Simon Kaufmann - initial contribution and API.
*
*/
@Singleton
public class RegistryProvider implements Provider<IResourceServiceProvider.Registry> {

private static IResourceServiceProvider.Registry registry = createRegistry();

@Override
public IResourceServiceProvider.Registry get() {
return registry;
}

private static Registry createRegistry() {
IResourceServiceProvider.Registry registry = new ResourceServiceProviderRegistryImpl();
register(registry, new ItemsIdeSetup().createInjector());
register(registry, new PersistenceIdeSetup().createInjector());
register(registry, new RulesIdeSetup().createInjector());
register(registry, new ScriptIdeSetup().createInjector());
register(registry, new SitemapIdeSetup().createInjector());
register(registry, new ThingIdeSetup().createInjector());
return registry;
}

private static void register(IResourceServiceProvider.Registry registry, Injector injector) {
IResourceServiceProvider resourceServiceProvider = injector.getInstance(IResourceServiceProvider.class);
FileExtensionProvider extensionProvider = injector.getInstance(FileExtensionProvider.class);
for (String ext : extensionProvider.getFileExtensions()) {
if (registry.getExtensionToFactoryMap().containsKey(ext)) {
if (extensionProvider.getPrimaryFileExtension() == ext) {
registry.getExtensionToFactoryMap().put(ext, resourceServiceProvider);
}
} else {
registry.getExtensionToFactoryMap().put(ext, resourceServiceProvider);
}
}
}

}
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.model.lsp.internal;

import java.util.concurrent.ExecutorService;

import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.xtext.ide.ExecutorServiceProvider;
import org.eclipse.xtext.ide.server.DefaultProjectDescriptionFactory;
import org.eclipse.xtext.ide.server.IProjectDescriptionFactory;
import org.eclipse.xtext.ide.server.IWorkspaceConfigFactory;
import org.eclipse.xtext.ide.server.LanguageServerImpl;
import org.eclipse.xtext.ide.server.ProjectWorkspaceConfigFactory;
import org.eclipse.xtext.resource.IContainer;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.containers.ProjectDescriptionBasedContainerManager;

import com.google.inject.AbstractModule;

/**
* This class configures the injector for the Language Server.
*
* @author Simon Kaufmann - initial contribution and API.
*
*/
public class RuntimeServerModule extends AbstractModule {

@Override
protected void configure() {
binder().bind(ExecutorService.class).toProvider(ExecutorServiceProvider.class);

bind(LanguageServer.class).to(LanguageServerImpl.class);
bind(IResourceServiceProvider.Registry.class).toProvider(RegistryProvider.class);
bind(IWorkspaceConfigFactory.class).to(ProjectWorkspaceConfigFactory.class);
bind(IProjectDescriptionFactory.class).to(DefaultProjectDescriptionFactory.class);
bind(IContainer.Manager.class).to(ProjectDescriptionBasedContainerManager.class);
}

}
Expand Up @@ -6,8 +6,9 @@ Bundle-SymbolicName: org.eclipse.smarthome.model.persistence.ide
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.9.0.qualifier
Export-Package:
org.eclipse.smarthome.model.persistence.ide,
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr,
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr.interna
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr.interna
l
Import-Package: org.eclipse.jdt.annotation;resolution:=optional
Require-Bundle:
Expand Down
Expand Up @@ -6,6 +6,7 @@ Bundle-SymbolicName: org.eclipse.smarthome.model.rule.ide
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.9.0.qualifier
Export-Package:
org.eclipse.smarthome.model.rule.ide,
org.eclipse.smarthome.model.rule.ide.contentassist.antlr,
org.eclipse.smarthome.model.rule.ide.contentassist.antlr.internal
Import-Package: org.eclipse.jdt.annotation;resolution:=optional
Expand Down
Expand Up @@ -6,6 +6,7 @@ Bundle-SymbolicName: org.eclipse.smarthome.model.script.ide
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.9.0.qualifier
Export-Package:
org.eclipse.smarthome.model.script.ide,
org.eclipse.smarthome.model.script.ide.contentassist.antlr,
org.eclipse.smarthome.model.script.ide.contentassist.antlr.internal
Import-Package: org.eclipse.jdt.annotation;resolution:=optional
Expand Down
Expand Up @@ -6,6 +6,7 @@ Bundle-SymbolicName: org.eclipse.smarthome.model.sitemap.ide
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.9.0.qualifier
Export-Package:
org.eclipse.smarthome.model.ide,
org.eclipse.smarthome.model.ide.contentassist.antlr,
org.eclipse.smarthome.model.ide.contentassist.antlr.internal
Import-Package: org.eclipse.jdt.annotation;resolution:=optional
Expand Down