diff --git a/src/main/java/com/microsoft/azure/functions/worker/Application.java b/src/main/java/com/microsoft/azure/functions/worker/Application.java index 4ea842e4..d20436af 100644 --- a/src/main/java/com/microsoft/azure/functions/worker/Application.java +++ b/src/main/java/com/microsoft/azure/functions/worker/Application.java @@ -1,11 +1,16 @@ package com.microsoft.azure.functions.worker; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; import java.util.logging.*; import javax.annotation.*; import org.apache.commons.cli.*; import org.apache.commons.lang3.exception.ExceptionUtils; +import static com.microsoft.azure.functions.worker.Constants.*; + /** * The entry point of the Java Language Worker. Every component could get the command line options from this singleton * Application instance, and typically that instance will be passed to your components as constructor arguments. @@ -15,36 +20,17 @@ private Application(String[] args) { this.parseCommandLine(args); } - @Override - public String getHost() { return this.host; } - @Override - public int getPort() { return this.port; } - @Override - public boolean logToConsole() { return this.logToConsole; } - @Override - public Integer getMaxMessageSize() { return this.maxMessageSize; } - private String getWorkerId() { return this.workerId; } - private String getRequestId() { return this.requestId; } - - private void printUsage() { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("Application", this.OPTIONS, true); - } - - private boolean isCommandlineValid() { return this.commandParseSucceeded; } - @PostConstruct private void parseCommandLine(String[] args) { CommandLineParser parser = new DefaultParser(); try { - CommandLine commands = parser.parse(this.OPTIONS, args); - this.host = this.parseHost(commands.getOptionValue("h")); - this.port = this.parsePort(commands.getOptionValue("p")); - this.workerId = this.parseWorkerId(commands.getOptionValue("w")); - this.requestId = this.parseRequestId(commands.getOptionValue("q")); - this.logToConsole = commands.hasOption("l"); - if (commands.hasOption("m")) { - this.maxMessageSize = this.parseMaxMessageSize(commands.getOptionValue("m")); + CommandLine commands = parser.parse(this.OPTIONS, args, true); + this.uri = this.parseUri(commands.getOptionValue(FUNCTIONS_URI_OPTION)); + this.workerId = this.parseWorkerId(commands.getOptionValue(FUNCTIONS_WORKER_ID_OPTION)); + this.requestId = this.parseRequestId(commands.getOptionValue(FUNCTIONS_REQUEST_ID_OPTION)); + this.logToConsole = commands.hasOption(FUNCTIONS_CONSOLE_LOG_OPTION); + if (commands.hasOption(FUNCTIONS_GRPC_MAX_MESSAGE_LENGTH_OPTION)) { + this.maxMessageSize = this.parseMaxMessageSize(commands.getOptionValue(FUNCTIONS_GRPC_MAX_MESSAGE_LENGTH_OPTION)); } this.commandParseSucceeded = true; } catch (ParseException ex) { @@ -53,84 +39,123 @@ private void parseCommandLine(String[] args) { } } - private String parseHost(String input) { return input; } - - private int parsePort(String input) throws ParseException { - try { - int result = Integer.parseInt(input); - if (result < 1 || result > 65535) { - throw new IndexOutOfBoundsException("port number out of range"); + public static void main(String[] args) { + WorkerLogManager.getSystemLogger().log(Level.INFO, "Azure Functions Java Worker version [ " + version() + "]"); + Application app = new Application(args); + if (!app.isCommandlineValid()) { + app.printUsage(); + System.exit(1); + } else { + try (JavaWorkerClient client = new JavaWorkerClient(app)) { + client.listen(app.getWorkerId(), app.getRequestId()).get(); + } catch (Exception ex) { + WorkerLogManager.getSystemLogger().log(Level.SEVERE, ExceptionUtils.getRootCauseMessage(ex), ex); + System.exit(-1); } - return result; - } catch (NumberFormatException | IndexOutOfBoundsException ex) { - throw new ParseException(String.format( - "port number \"%s\" is not qualified. It must be an integer within range [1, 65535]", input)); } } - private String parseRequestId(String input) { return input; } - - private String parseWorkerId(String input) { return input; } - - private Integer parseMaxMessageSize(String input) { - return Integer.parseInt(input); - } - private boolean commandParseSucceeded = false; - private String host; + private String uri, host, workerId, requestId; private int port; - private String workerId, requestId; private boolean logToConsole; private Integer maxMessageSize = null; - private final Options OPTIONS = new Options() - .addOption(Option.builder("h").longOpt("host") - .hasArg().argName("HostName") - .desc("The address of the machine that the Azure Functions host is running on") - .required() - .build()) - .addOption(Option.builder("p").longOpt("port") - .hasArg().argName("PortNumber") - .desc("The port number which the Azure Functions host is listening to") + .addOption(Option.builder("u").longOpt(FUNCTIONS_URI_OPTION) + .hasArg().argName("Uri") + .desc("The uri of the machine that the Azure Functions host is running on") .required() .build()) - .addOption(Option.builder("w").longOpt("workerId") + .addOption(Option.builder("w").longOpt(FUNCTIONS_WORKER_ID_OPTION) .hasArg().argName("WorkerId") .desc("The ID of this running worker throughout communication session") .required() .build()) - .addOption(Option.builder("q").longOpt("requestId") + .addOption(Option.builder("q").longOpt(FUNCTIONS_REQUEST_ID_OPTION) .hasArg().argName("RequestId") .desc("The startup request ID of this communication session") .required() .build()) - .addOption(Option.builder("l").longOpt("consoleLog") - .desc("Whether to duplicate all host logs to console as well") - .build()) - .addOption(Option.builder("m").longOpt("grpcMaxMessageLength") + .addOption(Option.builder("l").longOpt(FUNCTIONS_GRPC_MAX_MESSAGE_LENGTH_OPTION) .hasArg().argName("MessageSizeInBytes") .desc("The maximum message size could be used by GRPC protocol") + .build()) + .addOption(Option.builder("m").longOpt(FUNCTIONS_CONSOLE_LOG_OPTION) + .desc("Whether to duplicate all host logs to console as well") .build()); + @Override + public String getHost() { + return this.host; + } - public static void main(String[] args) { - WorkerLogManager.getSystemLogger().log(Level.INFO, "Azure Functions Java Worker version [ " + version() + "]"); - Application app = new Application(args); - if (!app.isCommandlineValid()) { - app.printUsage(); - System.exit(1); - } else { - try (JavaWorkerClient client = new JavaWorkerClient(app)) { - client.listen(app.getWorkerId(), app.getRequestId()).get(); - } catch (Exception ex) { - WorkerLogManager.getSystemLogger().log(Level.SEVERE, ExceptionUtils.getRootCauseMessage(ex), ex); - System.exit(-1); + @Override + public int getPort() { + return this.port; + } + + public String getUri() { + return this.uri; + } + + @Override + public boolean logToConsole() { + return this.logToConsole; + } + + @Override + public Integer getMaxMessageSize() { + return this.maxMessageSize; + } + + private String getWorkerId() { + return this.workerId; + } + + private String getRequestId() { + return this.requestId; + } + + private boolean isCommandlineValid() { + return this.commandParseSucceeded; + } + + private String parseUri(String uri) throws ParseException { + try { + URL url = new URL(uri); + url.toURI(); + this.host = url.getHost(); + this.port = url.getPort(); + if (port < 1 || port > 65535) { + throw new IndexOutOfBoundsException("port number out of range"); } + return uri; + } catch (MalformedURLException | URISyntaxException | IndexOutOfBoundsException e) { + throw new ParseException(String.format( + "Error parsing URI \"%s\". Please provide a valid URI", uri)); } } + private String parseRequestId(String input) { + return input; + } + + private String parseWorkerId(String input) { + return input; + } + + private Integer parseMaxMessageSize(String input) { + return Integer.parseInt(input); + } + public static String version() { String jarVersion = Application.class.getPackage().getImplementationVersion(); return jarVersion != null && !jarVersion.isEmpty() ? jarVersion : "Unknown"; } + + private void printUsage() { + HelpFormatter formatter = new HelpFormatter(); + formatter.setWidth(100); + formatter.printHelp("Application", this.OPTIONS, true); + } } diff --git a/src/main/java/com/microsoft/azure/functions/worker/Constants.java b/src/main/java/com/microsoft/azure/functions/worker/Constants.java index ed5a1e32..b9f2216b 100644 --- a/src/main/java/com/microsoft/azure/functions/worker/Constants.java +++ b/src/main/java/com/microsoft/azure/functions/worker/Constants.java @@ -5,6 +5,12 @@ */ public final class Constants { private Constants(){} + + public final static String FUNCTIONS_URI_OPTION = "functions-uri"; + public final static String FUNCTIONS_WORKER_ID_OPTION = "functions-worker-id"; + public final static String FUNCTIONS_REQUEST_ID_OPTION = "functions-request-id"; + public final static String FUNCTIONS_GRPC_MAX_MESSAGE_LENGTH_OPTION = "functions-grpc-max-message-length"; + public final static String FUNCTIONS_CONSOLE_LOG_OPTION = "functions-console-log"; public final static String TRIGGER_METADATA_DOLLAR_REQUEST_KEY = "$request"; public final static String JAVA_LIBRARY_DIRECTORY = "/annotationLib"; public final static String JAVA_LIBRARY_ARTIFACT_ID = "azure-functions-java-library";