Skip to content

Commit

Permalink
Added wrapper to scala classes and configured a new ExecutionContext
Browse files Browse the repository at this point in the history
  • Loading branch information
dsalathe committed Aug 31, 2023
1 parent b07526f commit aea4702
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 39 deletions.
6 changes: 3 additions & 3 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

<!-- Appender to write logs to a file -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/myapp.log</file> <!-- Change the file name as needed -->
<file>logs/sdl-lsp.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>logs/myapp.%i.log</fileNamePattern>
<fileNamePattern>logs/sdl-lsp.%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
Expand All @@ -21,4 +21,4 @@
<appender-ref ref="FILE"/>
</root>

</configuration>
</configuration>
43 changes: 34 additions & 9 deletions src/main/scala/io/smartdatalake/Main.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package io.smartdatalake

import io.smartdatalake.logging.LoggingManager
import ch.qos.logback.classic.Level
import io.smartdatalake.logging.{LoggerOutputStream, LoggingManager}
import io.smartdatalake.modules.AppModule
import jdk.jshell.spi.ExecutionControlProvider
import org.eclipse.lsp4j.jsonrpc.Launcher
import org.eclipse.lsp4j.launch.LSPLauncher
import org.eclipse.lsp4j.services.{LanguageClient, LanguageClientAware, LanguageServer}

import java.io.{InputStream, OutputStream, PrintStream}
import java.io.{InputStream, OutputStream, PrintStream, PrintWriter}
import org.slf4j.LoggerFactory

import java.util.concurrent.Executors
import scala.concurrent.ExecutionContext
import scala.util.control.NonFatal

/**
* @author scalathe
*/
Expand All @@ -29,15 +35,34 @@ object Main extends AppModule {
}

private def startServer(in: InputStream, out: PrintStream) = {
val logger = LoggerFactory.getLogger(getClass)
val helloLanguageServer: LanguageServer & LanguageClientAware = languageServer
val launcher: Launcher[LanguageClient] = LSPLauncher.createServerLauncher(helloLanguageServer, in, out)
val client: LanguageClient = launcher.getRemoteProxy

helloLanguageServer.connect(client)
// Use the configured logger
val logger = LoggerFactory.getLogger(getClass)
logger.info("Server starts listening...")
launcher.startListening().get()
try
val launcher: Launcher[LanguageClient] = Launcher.Builder[LanguageClient]()
.traceMessages(PrintWriter(LoggingManager.createPrintStreamWithLoggerName("jsonRpcLogger", level = Level.TRACE)))
.setExecutorService(executorService)
.setInput(in)
.setOutput(out)
.setRemoteInterface(classOf[LanguageClient])
.setLocalService(helloLanguageServer)
.create()

val client: LanguageClient = launcher.getRemoteProxy
helloLanguageServer.connect(client)
// Use the configured logger
logger.info("Server starts listening...")
launcher.startListening().get()
catch
case NonFatal(ex) =>
ex.printStackTrace(out)
logger.error(ex.toString)

finally
// Might want to also give capabilities to let the server shutdown itself more properly
executionContext.shutdownNow()
executorService.shutdownNow()
sys.exit(0)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import org.eclipse.lsp4j.{CompletionItem, CompletionItemKind}
import scala.util.{Failure, Success, Try}

class SDLBCompletionEngineImpl(private val schemaReader: SchemaReader) extends SDLBCompletionEngine {

//val schemaReader: SchemaReader = new SchemaReaderImpl("sdl-schema/sdl-schema-2.5.0.json") //TODO should be retrieved from a service keeping its state, object for example


override def generateCompletionItems(context: SDLBContext): List[CompletionItem] = context.parentPath match
case path if path.startsWith("actions") && path.count(_ == '.') == 1 => generatePropertiesOfAction(context)
case "actions" => generateTemplatesForAction()
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/io/smartdatalake/context/TextContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ case class TextContext private (originalText: String, configText: String, config
case _ => updateContext(newText)

private def updateContext(newText: String) =
val newConfigText = MultiLineTransformer.flattenMultiLines(newText) // For now. We'll see how to optimize incr. parsing and how to handle multiple files later
val newConfigText = MultiLineTransformer.flattenMultiLines(newText)
val newConfig = HoconParser.parse(newConfigText).getOrElse(HoconParser.EMPTY_CONFIG)
if newConfig == HoconParser.EMPTY_CONFIG then this else TextContext(newText, newConfigText, newConfig)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.smartdatalake.conversions

import java.util.concurrent.CompletableFuture
import org.eclipse.lsp4j.jsonrpc.messages
import scala.concurrent.Future
import scala.jdk.FutureConverters.*
import scala.jdk.CollectionConverters.*

trait ScalaJavaConverter {

extension [T] (f: Future[T]) def toJava: CompletableFuture[T] = f.asJava.toCompletableFuture

extension [T] (l: List[T]) def toJava: java.util.List[T] = l.asJava

extension [L, R] (either: Either[L, R]) def toJava: messages.Either[L, R] = either match
case Left(leftValue) => messages.Either.forLeft(leftValue)
case Right(rightValue) => messages.Either.forRight(rightValue)

}

object ScalaJavaConverterAPI extends ScalaJavaConverter
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package io.smartdatalake.languageserver

import io.smartdatalake.languageserver.{SmartDataLakeTextDocumentService, SmartDataLakeWorkspaceService}
import io.smartdatalake.conversions.ScalaJavaConverterAPI.*
import org.eclipse.lsp4j.services.*
import org.eclipse.lsp4j.*

import java.util.concurrent.CompletableFuture
import scala.concurrent.{ExecutionContext, Future}

class SmartDataLakeLanguageServer(private val textDocumentService: TextDocumentService, private val workspaceService: WorkspaceService) extends LanguageServer with LanguageClientAware {

class SmartDataLakeLanguageServer(private val textDocumentService: TextDocumentService, private val workspaceService: WorkspaceService)(using ExecutionContext) extends LanguageServer with LanguageClientAware {
private var client: Option[LanguageClient] = None
private var errorCode = 1

override def initialize(initializeParams: InitializeParams): CompletableFuture[InitializeResult] = {
val initializeResult = new InitializeResult(new ServerCapabilities)
val initializeResult = InitializeResult(ServerCapabilities())
initializeResult.getCapabilities.setTextDocumentSync(TextDocumentSyncKind.Full)
val completionOptions = new CompletionOptions
val completionOptions = CompletionOptions()
initializeResult.getCapabilities.setCompletionProvider(completionOptions)

initializeResult.getCapabilities.setHoverProvider(true)

CompletableFuture.supplyAsync(() => initializeResult)
Future(initializeResult).toJava
}

override def shutdown(): CompletableFuture[AnyRef] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ import io.smartdatalake.completion.{SDLBCompletionEngine, SDLBCompletionEngineIm
import io.smartdatalake.context.SDLBContext
import io.smartdatalake.hover.{SDLBHoverEngine, SDLBHoverEngineImpl}
import io.smartdatalake.schema.SchemaReader
import io.smartdatalake.conversions.ScalaJavaConverterAPI.*
import org.eclipse.lsp4j.jsonrpc.messages
import org.eclipse.lsp4j.services.TextDocumentService
import org.eclipse.lsp4j.{CodeAction, CodeActionParams, CodeLens, CodeLensParams, Command, CompletionItem, CompletionItemKind, CompletionList, CompletionParams, DefinitionParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFormattingParams, DocumentHighlight, DocumentHighlightParams, DocumentOnTypeFormattingParams, DocumentRangeFormattingParams, DocumentSymbol, DocumentSymbolParams, Hover, HoverParams, InsertReplaceEdit, Location, LocationLink, MarkupContent, MarkupKind, Position, Range, ReferenceParams, RenameParams, SignatureHelp, SignatureHelpParams, SymbolInformation, TextDocumentPositionParams, TextEdit, WorkspaceEdit}

import java.util
import java.util.concurrent.CompletableFuture
import scala.concurrent.{ExecutionContext, Future}
import scala.io.Source
import scala.util.Using

class SmartDataLakeTextDocumentService(private val completionEngine: SDLBCompletionEngine, private val hoverEngine: SDLBHoverEngine) extends TextDocumentService {
class SmartDataLakeTextDocumentService(private val completionEngine: SDLBCompletionEngine, private val hoverEngine: SDLBHoverEngine)(using ExecutionContext) extends TextDocumentService {

private var context: SDLBContext = SDLBContext.EMPTY_CONTEXT

override def completion(params: CompletionParams): CompletableFuture[messages.Either[util.List[CompletionItem], CompletionList]] = {

CompletableFuture.supplyAsync(() => {
context = context.withCaretPosition(params.getPosition.getLine+1, params.getPosition.getCharacter)
val completionItems = new util.ArrayList[CompletionItem]()
val suggestions: List[CompletionItem] = completionEngine.generateCompletionItems(context)
suggestions.foreach(e => completionItems.add(e))
Future {
val caretContext = context.withCaretPosition(params.getPosition.getLine+1, params.getPosition.getCharacter)
val completionItems: util.List[CompletionItem] = completionEngine.generateCompletionItems(caretContext).toJava
Left(completionItems).toJava
}.toJava

messages.Either.forLeft(completionItems).asInstanceOf[messages.Either[util.List[CompletionItem], CompletionList]]
})
}

override def didOpen(didOpenTextDocumentParams: DidOpenTextDocumentParams): Unit =
Expand All @@ -50,10 +50,10 @@ class SmartDataLakeTextDocumentService(private val completionEngine: SDLBComplet
override def resolveCompletionItem(completionItem: CompletionItem): CompletableFuture[CompletionItem] = ???

override def hover(params: HoverParams): CompletableFuture[Hover] = {
CompletableFuture.supplyAsync(() => {
Future {
val hoverContext = context.withCaretPosition(params.getPosition.getLine + 1, params.getPosition.getCharacter)
hoverEngine.generateHoveringInformation(hoverContext)
})
}.toJava
}

override def signatureHelp(params: SignatureHelpParams): CompletableFuture[SignatureHelp] = super.signatureHelp(params)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.smartdatalake.logging

import ch.qos.logback.classic.Level
import org.slf4j.Logger

import java.io.OutputStream

private[logging] class LoggerOutputStream(logger: Logger) extends OutputStream {
private[logging] class LoggerOutputStream(write: String => Unit) extends OutputStream {
private val builder = new StringBuilder
override def write(b: Int): Unit = {
if (b == '\n') {
logger.info(builder.toString)
write(builder.toString)
builder.clear()
} else {
builder.append(b.toChar)
Expand Down
14 changes: 12 additions & 2 deletions src/main/scala/io/smartdatalake/logging/LoggingManager.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package io.smartdatalake.logging

import ch.qos.logback.classic.Level
import org.slf4j.LoggerFactory

import java.io.PrintStream

object LoggingManager {

def redirectStandardOutputToLoggerOutput(): Unit =
val loggerRedirectedOutput = LoggerFactory.getLogger("redirectedOutput")
val redirectedPrintStream = new PrintStream(new LoggerOutputStream(loggerRedirectedOutput))
val redirectedPrintStream = createPrintStreamWithLoggerName("redirectedOutput")
System.setOut(redirectedPrintStream)
println("Using new default output stream")

def createPrintStreamWithLoggerName(loggerName: String, level: Level = Level.INFO): PrintStream =
val logger = LoggerFactory.getLogger(loggerName)
val printMethod: String => Unit = level match
case Level.TRACE => logger.trace
case Level.DEBUG => logger.debug
case Level.INFO => logger.info
case Level.WARN => logger.warn
case Level.ERROR => logger.error
PrintStream(LoggerOutputStream(printMethod))

}
9 changes: 7 additions & 2 deletions src/main/scala/io/smartdatalake/modules/AppModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import io.smartdatalake.languageserver.{SmartDataLakeLanguageServer, SmartDataLa
import io.smartdatalake.schema.{SchemaReader, SchemaReaderImpl}
import org.eclipse.lsp4j.services.{LanguageClientAware, LanguageServer, TextDocumentService, WorkspaceService}

import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService}

trait AppModule {
lazy val schemaReader: SchemaReader = new SchemaReaderImpl("sdl-schema/sdl-schema-2.5.0.json")
lazy val completionEngine: SDLBCompletionEngine = new SDLBCompletionEngineImpl(schemaReader)
lazy val hoverEngine: SDLBHoverEngine = new SDLBHoverEngineImpl(schemaReader)
lazy val textDocumentService: TextDocumentService = new SmartDataLakeTextDocumentService(completionEngine, hoverEngine)
lazy val executorService: ExecutorService = Executors.newCachedThreadPool()
lazy val executionContext: ExecutionContext & ExecutorService = ExecutionContext.fromExecutorService(executorService)
lazy val textDocumentService: TextDocumentService = new SmartDataLakeTextDocumentService(completionEngine, hoverEngine)(using executionContext)
lazy val workspaceService: WorkspaceService = new SmartDataLakeWorkspaceService
lazy val languageServer: LanguageServer & LanguageClientAware = new SmartDataLakeLanguageServer(textDocumentService, workspaceService)
lazy val languageServer: LanguageServer & LanguageClientAware = new SmartDataLakeLanguageServer(textDocumentService, workspaceService)(using executionContext)

}

2 changes: 1 addition & 1 deletion src/test/scala/io/smartdatalake/modules/TestModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import io.smartdatalake.schema.{SchemaReader, SchemaReaderImpl}
trait TestModule extends AppModule {
override lazy val schemaReader: SchemaReader = new SchemaReaderImpl("fixture/sdl-schema/sdl-schema-2.5.0.json")
override lazy val completionEngine: SDLBCompletionEngineImpl = new SDLBCompletionEngineImpl(schemaReader)
override lazy val languageServer: SmartDataLakeLanguageServer = new SmartDataLakeLanguageServer(textDocumentService, workspaceService)
override lazy val languageServer: SmartDataLakeLanguageServer = new SmartDataLakeLanguageServer(textDocumentService, workspaceService)(using executionContext)

}

0 comments on commit aea4702

Please sign in to comment.