From 0c8c9c8fe67e5817561ec583f7639c59a95352dc Mon Sep 17 00:00:00 2001
From: Alexander Diewald <diewald@fortiss.org>
Date: Wed, 15 Apr 2020 18:07:58 +0200
Subject: [PATCH] Kernel: Add a CLI service

* Allows registering command line switches and their handlers from
  plugin activators (start method).
* The handler execution must be executed after ALL other services were
  started. For instance, this can be done from the RCP.
* Handlers support consuming a switch and an additional argument.

Issue-Ref: 3993
Issue-Url: https://af3-developer.fortiss.org/issues/3993
Signed-off-by: Alexander Diewald <diewald@fortiss.org>
---
 .../fortiss/tooling/kernel/extension/.ratings |  1 +
 .../extension/ICommandLineSwitchHandler.java  | 37 ++++++++
 .../fortiss/tooling/kernel/internal/.ratings  |  1 +
 .../internal/CommandLineInterfaceService.java | 94 +++++++++++++++++++
 .../fortiss/tooling/kernel/service/.ratings   |  1 +
 .../service/ICommandLineInterfaceService.java | 47 ++++++++++
 6 files changed, 181 insertions(+)
 create mode 100644 org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/ICommandLineSwitchHandler.java
 create mode 100644 org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/CommandLineInterfaceService.java
 create mode 100644 org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/ICommandLineInterfaceService.java

diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings
index 5e2380be4..1ee9c9e35 100644
--- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings
@@ -1,3 +1,4 @@
+ICommandLineSwitchHandler.java 1df397bf5b1a2af7040f5e73bfe7f3bd239d47c5 YELLOW
 IConnectionCompositor.java 82188750593a08df75a5f21fd91d4b41f72593fd GREEN
 IConstraintChecker.java a6d76e332ece919adb990397dd5ef6aaa542ea7d GREEN
 IEclipseResourcePostLoadProvider.java e842bb7485ef27917092ffc60af8a57e475d01d6 GREEN
diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/ICommandLineSwitchHandler.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/ICommandLineSwitchHandler.java
new file mode 100644
index 000000000..1df397bf5
--- /dev/null
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/ICommandLineSwitchHandler.java
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------+
+| Copyright 2020 fortiss GmbH                                              |
+|                                                                          |
+| Licensed under the Apache License, Version 2.0 (the "License");          |
+| you may not use this file except in compliance with the License.         |
+| You may obtain a copy of the License at                                  |
+|                                                                          |
+|    http://www.apache.org/licenses/LICENSE-2.0                            |
+|                                                                          |
+| Unless required by applicable law or agreed to in writing, software      |
+| distributed under the License is distributed on an "AS IS" BASIS,        |
+| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+| See the License for the specific language governing permissions and      |
+| limitations under the License.                                           |
++--------------------------------------------------------------------------*/
+package org.fortiss.tooling.kernel.extension;
+
+/**
+ * Defines an entry point to process command line arguments following a switch. Each implementing
+ * class must be accompanied with an extension point definition that defines the (string) identifier
+ * of the switch. The registered classes are executed after all services are started.
+ * 
+ * @author diewald
+ */
+public interface ICommandLineSwitchHandler {
+
+	/** Indicates whether the handler expects an additional argument after the registered switch. */
+	boolean hasAdditionalArgument();
+
+	/**
+	 * Entry point to handle the given {@code argument} given at the command line.
+	 * 
+	 * @param argument
+	 *            String argument following a switch's identifier .
+	 */
+	void handleCLISwitch(String argument);
+}
diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings
index deae784c2..788c8c7c5 100644
--- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings
@@ -1,3 +1,4 @@
+CommandLineInterfaceService.java 6b5c94c52702f773c60b181eff52204ab379b248 YELLOW
 CommandStackService.java 957bda69b5feb91f002aed4d25ed334e92801e7e GREEN
 ConnectionCompositorService.java d69a60cd7a3d06e91d24fd32b9c00125ea71e0dd GREEN
 ConstraintCheckerService.java 459b5eb717598e7e8bb71a0c87e57ea85cb00e4b GREEN
diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/CommandLineInterfaceService.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/CommandLineInterfaceService.java
new file mode 100644
index 000000000..6b5c94c52
--- /dev/null
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/CommandLineInterfaceService.java
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------+
+| Copyright 2020 fortiss GmbH                                              |
+|                                                                          |
+| Licensed under the Apache License, Version 2.0 (the "License");          |
+| you may not use this file except in compliance with the License.         |
+| You may obtain a copy of the License at                                  |
+|                                                                          |
+|    http://www.apache.org/licenses/LICENSE-2.0                            |
+|                                                                          |
+| Unless required by applicable law or agreed to in writing, software      |
+| distributed under the License is distributed on an "AS IS" BASIS,        |
+| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+| See the License for the specific language governing permissions and      |
+| limitations under the License.                                           |
++--------------------------------------------------------------------------*/
+package org.fortiss.tooling.kernel.internal;
+
+import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Platform;
+import org.fortiss.tooling.kernel.ToolingKernelActivator;
+import org.fortiss.tooling.kernel.extension.ICommandLineSwitchHandler;
+import org.fortiss.tooling.kernel.service.ICommandLineInterfaceService;
+
+/**
+ * Implementation of the {@link ICommandLineInterfaceService}.
+ * 
+ * @author diewald
+ */
+public class CommandLineInterfaceService implements ICommandLineInterfaceService {
+
+	/** Singleton instance of the {@link ICommandLineInterfaceService} service. */
+	private static CommandLineInterfaceService INSTANCE = new CommandLineInterfaceService();
+
+	/** Guard for executing the CLI switch only once during the applications lifetime. */
+	private boolean handlersExecuted = false;
+
+	/** Associates CLI switches with their handlers. */
+	private Map<String, ICommandLineSwitchHandler> switchHandlerMap = new HashMap<>();
+
+	/** Hiding constructor. */
+	private CommandLineInterfaceService() {
+		// Prevent external instantiation.
+	}
+
+	/** Returns the {@link CommandLineInterfaceService} singleton. */
+	public static synchronized CommandLineInterfaceService getInstance() {
+		return INSTANCE;
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void executeHandlers() {
+		if(handlersExecuted) {
+			error(ToolingKernelActivator.getDefault(), "The " +
+					CommandLineInterfaceService.class.getSimpleName() +
+					" was asked more than one to process command line switches. The subsequent " +
+					"calls were NOT executed. Please report this issue to the developers.");
+			return;
+		}
+		handlersExecuted = true;
+
+		String[] args = Platform.getApplicationArgs();
+		for(int cliIdx = 0; cliIdx < args.length; ++cliIdx) {
+			String cliSwitch = args[cliIdx];
+			ICommandLineSwitchHandler cliHandler = switchHandlerMap.get(cliSwitch);
+			if(cliHandler != null) {
+				String argument =
+						cliHandler.hasAdditionalArgument() ? argument = args[++cliIdx] : null;
+				cliHandler.handleCLISwitch(argument);
+			} else {
+				error(ToolingKernelActivator.getDefault(),
+						"Could not parse the argument " + cliSwitch + ".");
+			}
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void registerHandler(String cliSwitch, ICommandLineSwitchHandler cliHandler) {
+		if(switchHandlerMap.containsKey(cliSwitch)) {
+			ICommandLineSwitchHandler activeHandler = switchHandlerMap.get(cliSwitch);
+			error(ToolingKernelActivator.getDefault(),
+					"The CLI switch " + cliSwitch + " is already registered with the handler " +
+							activeHandler.getClass().getSimpleName() + " and won't be replaced.");
+			return;
+		}
+
+		switchHandlerMap.put(cliSwitch, cliHandler);
+	}
+}
diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings
index c0b2fd39e..9ea5e6db4 100644
--- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/.ratings
@@ -1,3 +1,4 @@
+ICommandLineInterfaceService.java b8b67b758f9af720968279ef7af9e2ef4f393f62 YELLOW
 ICommandStackService.java 678dcd1a6ab435ed0870fa2a9ec48ce47f25a187 GREEN
 IConnectionCompositorService.java 0cdf4568b2cd3e95ea195df90a84699eff36442b GREEN
 IConstraintCheckerService.java 291e53297aaea213e07e78f63350938ee2c7b155 GREEN
diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/ICommandLineInterfaceService.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/ICommandLineInterfaceService.java
new file mode 100644
index 000000000..b8b67b758
--- /dev/null
+++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/service/ICommandLineInterfaceService.java
@@ -0,0 +1,47 @@
+/*-------------------------------------------------------------------------+
+| Copyright 2020 fortiss GmbH                                              |
+|                                                                          |
+| Licensed under the Apache License, Version 2.0 (the "License");          |
+| you may not use this file except in compliance with the License.         |
+| You may obtain a copy of the License at                                  |
+|                                                                          |
+|    http://www.apache.org/licenses/LICENSE-2.0                            |
+|                                                                          |
+| Unless required by applicable law or agreed to in writing, software      |
+| distributed under the License is distributed on an "AS IS" BASIS,        |
+| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+| See the License for the specific language governing permissions and      |
+| limitations under the License.                                           |
++--------------------------------------------------------------------------*/
+package org.fortiss.tooling.kernel.service;
+
+import org.fortiss.tooling.kernel.extension.ICommandLineSwitchHandler;
+import org.fortiss.tooling.kernel.internal.CommandLineInterfaceService;
+
+/**
+ * Service to register handlers for command line switches and their arguments. The handlers are
+ * executed after the startup of all other service to ensure the presence of the full feature set
+ * when this service is executed.
+ * 
+ * @author diewald
+ */
+public interface ICommandLineInterfaceService {
+
+	/** Returns the internal implemenation of the {@link ICommandLineInterfaceService}. */
+	public static ICommandLineInterfaceService getInstance() {
+		return CommandLineInterfaceService.getInstance();
+	}
+
+	/**
+	 * Executes the registered {@link ICommandLineSwitchHandler}s for the switches that have been
+	 * passed to the program executable. This method can be executed only once during the
+	 * application lifecycle, otherwise it degenerates to a no-op.
+	 */
+	void executeHandlers();
+
+	/**
+	 * Registers an {@link ICommandLineSwitchHandler} that is executed if the given switch has
+	 * been passed to the program executable.
+	 */
+	void registerHandler(String cliSwitch, ICommandLineSwitchHandler cliHandler);
+}
-- 
GitLab