Skip to content

Commit

Permalink
eclipse-glsp#95 Cleanup GLSPServerLauncher & add CLI parsing (eclipse…
Browse files Browse the repository at this point in the history
…-glsp#69)

* eclipse-glsp#95 Cleanup GLSPServerLauncher & add CLI parsing

- Cleanup GLSPServerLauncher (refactor methods & add support to inject additional modules)
- Add a CLIParser helper class and configure default options for configuring
-- Server port
-- consoleLog flag
-- logging directory
-- logLevel
-- help

Fixes eclipse-glsp/glsp/issues/95
  • Loading branch information
tortmayr authored Aug 14, 2020
1 parent 810a4ae commit add144a
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class WebsocketServerLauncher extends GLSPServerLauncher {
private static Logger LOG = Logger.getLogger(WebsocketServerLauncher.class);
private Server server;
Expand All @@ -41,21 +38,17 @@ public class WebsocketServerLauncher extends GLSPServerLauncher {
public WebsocketServerLauncher(final GLSPModule module, final String endpointPath) {
super(module);
this.endpointPath = endpointPath.startsWith("/") ? endpointPath.substring(1) : endpointPath;
addAdditionalModules(new WebsocketModule());
}

public WebsocketServerLauncher(final GLSPModule module, final String endpointPath, final String clientAppPath) {
this(module, endpointPath);
this.clientAppPath = clientAppPath;
}

@Override
protected Injector doSetup() {
return Guice.createInjector(getGLSPModule(), new WebsocketModule());
}

@Override
@SuppressWarnings("checkstyle:IllegalCatch")
public void run(final String hostname, final int port) {
public void start(final String hostname, final int port) {
try {
// Setup Jetty Server
server = new Server(new InetSocketAddress(hostname, port));
Expand All @@ -82,7 +75,7 @@ public void run(final String hostname, final int port) {
ServerContainer container = WebSocketServerContainerInitializer.configureContext(webAppContext);
ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(GLSPServerEndpoint.class,
"/" + endpointPath);
builder.configurator(new GLSPConfigurator(getInjector()));
builder.configurator(new GLSPConfigurator(createInjector()));
container.addEndpoint(builder.build());

// Start the server
Expand Down
3 changes: 2 additions & 1 deletion plugins/org.eclipse.glsp.server/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.glsp.api;bundle-version="0.7.0";visibility:=reexport
com.google.gson;bundle-version="2.8.2",
org.eclipse.lsp4j;bundle-version="0.7.0",
org.eclipse.lsp4j.jsonrpc,
com.google.guava;bundle-version="21.0.0"
com.google.guava;bundle-version="21.0.0",
org.apache.commons.cli;bundle-version="1.4.0";visibility:=reexport
Import-Package: com.google.inject.multibindings;version="1.3.0"
Export-Package: org.eclipse.glsp.server.actionhandler,
org.eclipse.glsp.server.command,
Expand Down
5 changes: 5 additions & 0 deletions plugins/org.eclipse.glsp.server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
<artifactId>org.eclipse.emf.ecore.change</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
package org.eclipse.glsp.server.launch;

import java.util.function.Predicate;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.eclipse.glsp.server.utils.LaunchUtil;

public abstract class CLIParser {
private static final Logger LOG = Logger.getLogger(CLIParser.class);
protected static final String INVALID_ARGUMENT_MESSAGE = "%s' is not a valid argument for option '--%s'! The default value '%s' is used.";

protected final CommandLine cmd;
protected final Options options;
protected final String processName;

public CLIParser(final String[] args, final Options options, final String processName) throws ParseException {
this.cmd = new DefaultParser().parse(options, args);
this.options = options;
this.processName = processName;
}

public boolean hasOption(final String optionName) {
return cmd.hasOption(optionName);
}

public String parseOption(final String optionName, final String defaultValue) {
return parseOption(optionName, defaultValue, null);
}

public String parseOption(final String optionName, final String defaultValue, final Predicate<String> validator) {
String arg = cmd.getOptionValue(optionName);
if (arg != null) {
if (validator == null || validator.test(arg)) {
return arg;
}
LOG.warn(String.format(INVALID_ARGUMENT_MESSAGE,
arg, optionName, defaultValue));
}
return defaultValue;
}

public int parseIntOption(final String optionName, final int defaultValue) {
return parseIntOption(optionName, defaultValue, null);
}

public int parseIntOption(final String optionName, final int defaultValue, final Predicate<Integer> validator) {
String intArg = cmd.getOptionValue(optionName);
int value = defaultValue;
if (intArg != null) {
try {
value = Integer.parseInt(intArg);
if (validator != null && !validator.test(value)) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
LOG.warn(String.format(INVALID_ARGUMENT_MESSAGE,
intArg, optionName, defaultValue));
}
}
return value;
}

public boolean parseBoolOption(final String optionName, final boolean defaultValue) {
String arg = cmd.getOptionValue(optionName);
return arg != null ? Boolean.parseBoolean(arg) : defaultValue;
}

public void printHelp() {
LaunchUtil.printHelp(this.processName, options);
}

public CommandLine getCmd() { return cmd; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
package org.eclipse.glsp.server.launch;

import java.io.File;
import java.util.function.Predicate;

import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Level;
import org.eclipse.glsp.server.utils.LaunchUtil;
import org.eclipse.glsp.server.utils.LaunchUtil.DefaultOptions;

public class DefaultCLIParser extends CLIParser {
public static final String OPTION_HELP = "help";
public static final String OPTION_PORT = "port";
public static final String OPTION_CONSOLE_LOG = "consoleLog";
public static final String OPTION_FILE_LOG = "fileLog";
public static final String OPTION_LOG_LEVEL = "logLevel";
public static final String OPTION_LOG_DIR = "logDir";

public DefaultCLIParser(final String[] args, final String processName) throws ParseException {
this(args, getDefaultOptions(), processName);
}

public DefaultCLIParser(final String[] args, final Options options, final String processName) throws ParseException {
super(args, options, processName);
}

public int parsePort() {
Predicate<Integer> validator = (port) -> LaunchUtil.isValidPort(port);
return parseIntOption(OPTION_PORT, DefaultOptions.SERVER_PORT, validator);
}

public String parseLogDir() {
Predicate<String> validator = (logDirArg) -> {
File file = new File(logDirArg);
return file.exists() && file.isDirectory();
};
String logDir = parseOption(OPTION_LOG_DIR, DefaultOptions.LOG_DIR, validator);
return new File(logDir).getAbsolutePath();
}

public Level parseLogLevel() {
String levelArg = parseOption(OPTION_LOG_LEVEL, DefaultOptions.LOG_LEVEL.toString());
return Level.toLevel(levelArg, DefaultOptions.LOG_LEVEL);
}

public boolean isConsoleLog() { return parseBoolOption(OPTION_CONSOLE_LOG, DefaultOptions.CONSOLE_LOG_ENABLED); }

public boolean isFileLog() { return parseBoolOption(OPTION_FILE_LOG, DefaultOptions.FILE_LOG_ENABLED); }

public boolean isHelp() { return hasOption(OPTION_HELP); }

public static Options getDefaultOptions() {
Options options = new Options();
options.addOption(null, OPTION_HELP, false, "Display usage information about GLSPServerLauncher");
options.addOption(null, OPTION_PORT, true,
String.format("Set server port. [default='%s']", DefaultOptions.SERVER_PORT));
options.addOption(null, OPTION_CONSOLE_LOG, true,
String.format("Enable/Disable console logging. [default='%s']", DefaultOptions.CONSOLE_LOG_ENABLED));
options.addOption(null, OPTION_FILE_LOG, true,
String.format("Enable/Disable file logging. [default='%s']", DefaultOptions.FILE_LOG_ENABLED));
options.addOption(null, OPTION_LOG_DIR, true,
String.format("Set the directory for log files (File logging has to be enabled). [default='%s']",
DefaultOptions.LOG_DIR));
options.addOption(null, OPTION_LOG_LEVEL, true,
String.format("Set the log level. [default='%s']", DefaultOptions.LOG_LEVEL));
return options;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.eclipse.lsp4j.jsonrpc.MessageConsumer;

import com.google.gson.GsonBuilder;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class DefaultGLSPServerLauncher extends GLSPServerLauncher {
Expand All @@ -50,22 +49,20 @@ public class DefaultGLSPServerLauncher extends GLSPServerLauncher {
private AsynchronousServerSocketChannel serverSocket;
private CompletableFuture<Void> onShutdown;

public DefaultGLSPServerLauncher(final GLSPModule module) {
super(module);
public DefaultGLSPServerLauncher(final GLSPModule glspModule) {
super(glspModule);
}

@Override
public void run(final String hostname, final int port) {
public void start(final String hostname, final int port) {
Future<Void> onClose;
try {
onClose = asyncRun(hostname, port);
onClose.get();
log.info("Stopped GLSP server");
} catch (IOException | InterruptedException | ExecutionException e) {
log.error(e.getMessage());
e.printStackTrace();
log.error("Error during server close!", e);
}

}

public Future<Void> asyncRun(final String hostname, final int port)
Expand All @@ -89,13 +86,13 @@ public void failed(final Throwable exc, final Void attachment) {
};

serverSocket.accept(null, handler);
log.info("The GLSP server is ready to accept new client requests");
log.info("The GLSP server is ready to accept new client requests on port: " + port);

return onShutdown;
}

private void createClientConnection(final AsynchronousSocketChannel socketChannel) {
Injector injector = Guice.createInjector(getGLSPModule());
Injector injector = createInjector();
GsonConfigurator gsonConf = injector.getInstance(GsonConfigurator.class);
try {
InputStream in = Channels.newInputStream(socketChannel);
Expand All @@ -117,7 +114,7 @@ private void createClientConnection(final AsynchronousSocketChannel socketChanne
try {
socketChannel.close();
} catch (IOException e) {
log.debug("Excpetion occured when trying to close socketChannel", e);
log.error("Excpetion occured when trying to close socketChannel", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,40 @@
********************************************************************************/
package org.eclipse.glsp.server.launch;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.glsp.api.di.GLSPModule;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

public abstract class GLSPServerLauncher {

private GLSPModule module;
private Injector injector;

public GLSPServerLauncher() {}
private final GLSPModule glspModule;
private final List<Module> modules;

public GLSPServerLauncher(final GLSPModule module) {
this.module = module;
public GLSPServerLauncher(final GLSPModule glspModule) {
this.glspModule = glspModule;
modules = new ArrayList<>();
modules.add(glspModule);
}

protected Injector doSetup() {
return Guice.createInjector(module);
public void addAdditionalModules(final Module... modules) {
Arrays.stream(modules)
.filter(module -> !this.modules.contains(module))
.forEach(this.modules::add);
}

public void start(final String hostname, final int port) {
if (injector == null) {
injector = doSetup();
}
run(hostname, port);
public Injector createInjector() {
return Guice.createInjector(modules);
}

protected abstract void run(String hostname, int port);
public abstract void start(String hostname, int port);

public abstract void shutdown();

public GLSPModule getGLSPModule() { return module; }

public Injector getInjector() { return injector; }

public void setModule(final GLSPModule module) { this.module = module; }
public GLSPModule getGLSPModule() { return glspModule; }
}
Loading

0 comments on commit add144a

Please sign in to comment.