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

Commit

Permalink
WIP: Exposing a Language Server
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
  • Loading branch information
sjsf committed Aug 28, 2017
1 parent aa7a492 commit dcd537a
Show file tree
Hide file tree
Showing 21 changed files with 398 additions and 14 deletions.
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
41 changes: 41 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/META-INF/MANIFEST.MF
@@ -0,0 +1,41 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse SmartHome Language Server
Bundle-SymbolicName: org.eclipse.smarthome.model.lsp;singleton:=true
Bundle-Version: 0.9.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
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.runtime,
org.eclipse.smarthome.model.persistence.runtime,
org.eclipse.smarthome.model.rule.runtime,
org.eclipse.smarthome.model.script.runtime,
org.eclipse.smarthome.model.sitemap.runtime,
org.eclipse.smarthome.model.thing.runtime,
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
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,
org.slf4j
Service-Component: OSGI-INF/*.xml
Bundle-Vendor: Eclipse.org/SmartHome
@@ -0,0 +1 @@
*.xml
43 changes: 43 additions & 0 deletions bundles/model/org.eclipse.smarthome.model.lsp/about.html
@@ -0,0 +1,43 @@

<!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>&lt;<em>September 15, 2014</em>&gt;</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>


<h3>Third Party Content</h3>
<p>The Content includes items that have been sourced from third parties as set out below. If you
did not receive this Content directly from the Eclipse Foundation, the following is provided
for informational purposes only, and you should look to the Redistributor's license for
terms and conditions of use.</p>
<p>
<strong>Joda-Time 2.3</strong> <br/><br/>
This bundle includes the <a href="http://www.joda.org/joda-time/">Joda-Time library</a>. The sources can be found at
<a href="https://github.com/JodaOrg/joda-time/tree/v2.3">Sourgeforge</a> and
they are made available under the <a href="about_files/LICENSE-2.0.txt">Apache 2.0 license</a>.
</p>


</body>
</html>
@@ -0,0 +1,5 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
OSGI-INF/
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,101 @@
/**
* 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 running 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.error("Error communicating with the LSP client", e);
} 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 @@ -9,6 +9,7 @@ Require-Bundle: org.eclipse.smarthome.model.persistence,
org.eclipse.xtext.ide,
org.antlr.runtime,
org.eclipse.xtext.xbase.lib
Export-Package: org.eclipse.smarthome.model.persistence.ide.contentassist.antlr.internal,
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr
Export-Package: org.eclipse.smarthome.model.persistence.ide,
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr,
org.eclipse.smarthome.model.persistence.ide.contentassist.antlr.internal

0 comments on commit dcd537a

Please sign in to comment.