tiagobento commented on code in PR #2165:
URL: 
https://github.com/apache/incubator-kie-tools/pull/2165#discussion_r1541385601


##########
packages/extended-services-vscode-extension/src/watchers/configurations/configuration.ts:
##########
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+
+export class Configuration {
+  static readonly autoRunConfigurationID: string = 
"extendedServices.enableAutorun";
+  static readonly serviceURLConfigurationID: string = 
"extendedServices.serviceURL";
+  static readonly connectionHeartbeatIntervalConfigurationID: string = 
"extendedServices.connectionHeartbeatInterval";
+
+  readonly autoRun: boolean;

Review Comment:
   ```suggestion
     readonly enableAutoRun: boolean;
   ```



##########
packages/vscode-extension/src/VsCodeRecommendation.ts:
##########
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+
+export class VsCodeRecommendation {
+  public static showExtendedServicesRecommendation(context: 
vscode.ExtensionContext) {
+    const message =
+      "There is another extension available that might help you.\n" +
+      "Click [here](command:bpmn-vscode-extension.installExtendedServices) to 
install it.";
+    const action = "Install Extended-Services VS Code Extension";
+
+    const disposable = 
vscode.commands.registerCommand("bpmn-vscode-extension.installExtendedServices",
 () => {
+      
vscode.env.openExternal(vscode.Uri.parse("vscode:extension/kie-group.extended-services-vscode-extension"));
+    });
+
+    vscode.window.showInformationMessage(message, action).then((selection) => {
+      if (selection === action) {
+        
vscode.commands.executeCommand("bpmn-vscode-extension.installExtendedServices");
+      }
+    });
+
+    context.subscriptions.push(disposable);
+  }
+}

Review Comment:
   BPMN-specific commands here...



##########
packages/extended-services-vscode-extension/src/watchers/kie-files/kie-file.ts:
##########
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+
+export class KIEFile {
+  public readonly fsPath: string;

Review Comment:
   Please take this comment into consideration when naming variables that 
represent paths 
https://github.com/apache/incubator-kie-issues/issues/783#issuecomment-1871525975



##########
packages/extended-services-vscode-extension/src/local-service-manager.ts:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as childProcess from "child_process";
+import * as path from "path";
+import * as vscode from "vscode";
+
+export class LocalServiceManager {
+  readonly startLocalServiceCommandUID: string = 
"extended-services-vscode-extension.startLocalService";
+  readonly stopLocalServiceCommandUID: string = 
"extended-services-vscode-extension.stopLocalService";
+
+  private readonly relativePath: string = "/dist-dev/extended-services-java";
+  private readonly jarFileName: string = "quarkus-run.jar";
+
+  private localServiceRunningHandler: LocalServiceRunningHandler | null = null;
+  private localServiceTerminatedHandler: LocalServiceTerminatedHandler | null 
= null;
+
+  private context: vscode.ExtensionContext;
+  private startLocalServiceCommand: vscode.Disposable;
+  private stopLocalServiceCommand: vscode.Disposable;
+  private serviceProcess: childProcess.ChildProcess | undefined;
+
+  constructor(context: vscode.ExtensionContext) {
+    this.context = context;
+    this.initializeCommands();
+  }
+
+  private initializeCommands(): void {
+    const startLocalServiceCommandHandler = (serviceURL: URL) => {
+      this.start(serviceURL);
+    };
+
+    const stopLocalServiceCommandHandler = () => {
+      this.stop();
+    };
+
+    this.startLocalServiceCommand = vscode.commands.registerCommand(
+      this.startLocalServiceCommandUID,
+      startLocalServiceCommandHandler
+    );
+    this.stopLocalServiceCommand = vscode.commands.registerCommand(
+      this.stopLocalServiceCommandUID,
+      stopLocalServiceCommandHandler
+    );
+
+    this.context.subscriptions.push(this.startLocalServiceCommand);
+    this.context.subscriptions.push(this.stopLocalServiceCommand);
+  }
+
+  private fireLocalServicesRunningEvent() {
+    if (this.localServiceRunningHandler) {
+      this.localServiceRunningHandler();
+    }
+  }
+
+  private fireLocalServicesTerminatedEvent() {
+    if (this.localServiceTerminatedHandler) {
+      this.localServiceTerminatedHandler();
+    }
+  }
+
+  public subscribeLocalServicesRunning(handler: LocalServiceRunningHandler) {
+    this.localServiceRunningHandler = handler;
+  }
+
+  public subscribeLocalServicesTerminated(handler: 
LocalServiceTerminatedHandler) {
+    this.localServiceTerminatedHandler = handler;
+  }
+
+  public unsubscribeLocalServicesRunning() {
+    this.localServiceRunningHandler = null;
+  }
+
+  public unsubscribeLocalServicesTerminated() {
+    this.localServiceTerminatedHandler = null;
+  }
+
+  private runLocalService(serviceURL: URL): void {
+    const absolutePath = this.context.extensionPath;
+    const jarFilePath = path.join(absolutePath, this.relativePath, 
this.jarFileName);

Review Comment:
   Path variables... need better names.



##########
packages/extended-services-vscode-extension/src/extension/extension-main.ts:
##########
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import { Configuration } from "../watchers/configurations/configuration";
+import { ConfigurationWatcher } from 
"../watchers/configurations/configuration-watcher";
+import { ConnectionManager } from "../connection-manager";
+import { KIEFileWatcher } from "../watchers/kie-files/kie-file-watcher";
+import { LocalServiceManager } from "../local-service-manager";
+import { ValidationHelper } from "../validation-helper";
+
+const connectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.connectExtendedServices";
+const disconnectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.disconnectExtendedServices";
+const connectedEnablamentUID: string = 
"extended-services-vscode-extension.connected";
+
+let connectExtendedServicesCommand: vscode.Disposable;
+let disconnectExtendedServicesCommand: vscode.Disposable;
+
+let kieFileWatcher: KIEFileWatcher;
+let configurationWatcher: ConfigurationWatcher;
+let connectionManager: ConnectionManager;
+let localServiceManager: LocalServiceManager;
+let validationHelper: ValidationHelper;
+let statusBarItem: vscode.StatusBarItem;
+let userDisconnected: boolean;
+let connected: boolean;
+
+function connectExtendedServices(): void {
+  userDisconnected = false;
+  const configuration = Configuration.fetchConfiguration();
+  if (configuration) {
+    if (configuration.autoRun) {
+      
vscode.commands.executeCommand(localServiceManager.startLocalServiceCommandUID, 
configuration.serviceURL);
+    } else {
+      vscode.commands.executeCommand(
+        connectionManager.startConnectionHeartbeatCommandUID,
+        configuration.serviceURL,
+        configuration.connectionHeartbeatInterval
+      );
+    }
+  }
+}
+
+function disconnectExtendedServices(): void {
+  userDisconnected = true;
+  const configuration: Configuration | undefined = 
Configuration.fetchConfiguration();
+  if (configuration && configuration.autoRun) {
+    
vscode.commands.executeCommand(localServiceManager.stopLocalServiceCommandUID);
+  } else {
+    
vscode.commands.executeCommand(connectionManager.stopConnectionHeartbeatCommandUID);
+  }
+}
+
+function initializeCommands(context: vscode.ExtensionContext): void {
+  const connectExtendedServicesCommandHandler = () => {
+    connectExtendedServices();
+  };
+
+  const disconnectExtendedServicesCommandHandler = () => {
+    disconnectExtendedServices();
+  };
+
+  connectExtendedServicesCommand = vscode.commands.registerCommand(
+    connectExtendedServicesCommandUID,
+    connectExtendedServicesCommandHandler
+  );
+
+  disconnectExtendedServicesCommand = vscode.commands.registerCommand(
+    disconnectExtendedServicesCommandUID,
+    disconnectExtendedServicesCommandHandler
+  );
+
+  context.subscriptions.push(connectExtendedServicesCommand);
+  context.subscriptions.push(disconnectExtendedServicesCommand);
+}
+
+export function activate(context: vscode.ExtensionContext): void {
+  vscode.commands.executeCommand("setContext", connectedEnablamentUID, false);
+  userDisconnected = false;
+  connected = false;
+
+  statusBarItem = 
vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
+  statusBarItem.show();
+  context.subscriptions.push(statusBarItem);
+
+  kieFileWatcher = new KIEFileWatcher();
+  configurationWatcher = new ConfigurationWatcher();
+  localServiceManager = new LocalServiceManager(context);
+  connectionManager = new ConnectionManager(context);
+  validationHelper = new ValidationHelper(context);
+
+  initializeCommands(context);
+
+  configurationWatcher.subscribeSettingsChanged(() => {
+    if (!userDisconnected && connected) {
+      const configuration: Configuration | undefined = 
Configuration.fetchConfiguration();
+
+      if (configuration && configuration.autoRun) {
+        
vscode.commands.executeCommand(localServiceManager.stopLocalServiceCommandUID);
+      } else {
+        
vscode.commands.executeCommand(connectionManager.stopConnectionHeartbeatCommandUID);
+      }
+
+      if (configuration) {
+        if (configuration.autoRun) {
+          
vscode.commands.executeCommand(localServiceManager.startLocalServiceCommandUID, 
configuration.serviceURL);
+        } else {
+          vscode.commands.executeCommand(
+            connectionManager.startConnectionHeartbeatCommandUID,
+            configuration.serviceURL,
+            configuration.connectionHeartbeatInterval
+          );
+        }
+      }
+    }

Review Comment:
   Please do apply that reasoning to other parts of the code as well.



##########
packages/extended-services-vscode-extension/src/extension/extension-main.ts:
##########
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import { Configuration } from "../watchers/configurations/configuration";
+import { ConfigurationWatcher } from 
"../watchers/configurations/configuration-watcher";
+import { ConnectionManager } from "../connection-manager";
+import { KIEFileWatcher } from "../watchers/kie-files/kie-file-watcher";
+import { LocalServiceManager } from "../local-service-manager";
+import { ValidationHelper } from "../validation-helper";
+
+const connectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.connectExtendedServices";
+const disconnectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.disconnectExtendedServices";
+const connectedEnablamentUID: string = 
"extended-services-vscode-extension.connected";
+
+let connectExtendedServicesCommand: vscode.Disposable;
+let disconnectExtendedServicesCommand: vscode.Disposable;
+
+let kieFileWatcher: KIEFileWatcher;
+let configurationWatcher: ConfigurationWatcher;
+let connectionManager: ConnectionManager;
+let localServiceManager: LocalServiceManager;
+let validationHelper: ValidationHelper;
+let statusBarItem: vscode.StatusBarItem;
+let userDisconnected: boolean;
+let connected: boolean;
+
+function connectExtendedServices(): void {
+  userDisconnected = false;
+  const configuration = Configuration.fetchConfiguration();
+  if (configuration) {
+    if (configuration.autoRun) {
+      
vscode.commands.executeCommand(localServiceManager.startLocalServiceCommandUID, 
configuration.serviceURL);
+    } else {
+      vscode.commands.executeCommand(
+        connectionManager.startConnectionHeartbeatCommandUID,
+        configuration.serviceURL,
+        configuration.connectionHeartbeatInterval
+      );
+    }
+  }

Review Comment:
   What happens if there's no configuration?



##########
packages/extended-services-vscode-extension/src/validation-helper.ts:
##########
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import { BPMNValidationResponse, DMNValidationResponse } from 
"./jit-executor/responses";
+import { JITCommands } from "./jit-executor/jit-commands";
+import { KIEFileWatcher } from "./watchers/kie-files/kie-file-watcher";
+
+export class ValidationHelper {
+  readonly source = "Apache KIE Extended Services";
+  readonly clearValidationCommandUID: string = 
"extended-services-vscode-extension.clearValidation";
+  readonly validateCommandUID: string = 
"extended-services-vscode-extension.validate";
+
+  private context: vscode.ExtensionContext;
+  private clearValidationCommand: vscode.Disposable;
+  private validateCommand: vscode.Disposable;
+  private diagnosticCollection;
+
+  constructor(context: vscode.ExtensionContext) {
+    this.context = context;
+    this.diagnosticCollection = 
vscode.languages.createDiagnosticCollection("KIE Files Diagnostics");
+    this.initializeCommand();
+  }
+
+  private initializeCommand(): void {
+    const clearValidationCommandHandler = () => {
+      this.clearValidation();
+    };
+
+    const validateCommandHandler = (serviceURL: URL) => {
+      this.validate(serviceURL);
+    };
+
+    this.clearValidationCommand = vscode.commands.registerCommand(
+      this.clearValidationCommandUID,
+      clearValidationCommandHandler
+    );
+    this.validateCommand = 
vscode.commands.registerCommand(this.validateCommandUID, 
validateCommandHandler);
+
+    this.context.subscriptions.push(this.validateCommand);
+  }
+
+  private createBPMNDiagnostics(document: vscode.TextDocument, 
validationResponses: BPMNValidationResponse[]): void {
+    const diagnostics: vscode.Diagnostic[] = [];
+
+    for (const validationResponse of validationResponses) {
+      const diagnostic = new vscode.Diagnostic(
+        new vscode.Range(0, 0, 0, 0),
+        validationResponse.error,
+        vscode.DiagnosticSeverity.Error
+      );
+      diagnostic.source = this.source;
+      diagnostics.push(diagnostic);
+    }
+
+    this.diagnosticCollection.set(document.uri, diagnostics);
+  }
+
+  private createDMNDiagnostics(document: vscode.TextDocument, 
validationResponses: DMNValidationResponse[]): void {
+    const diagnostics: vscode.Diagnostic[] = [];
+
+    for (const validationResponse of validationResponses) {
+      const diagnostic = new vscode.Diagnostic(
+        new vscode.Range(0, 0, 0, 0),
+        validationResponse.message,
+        vscode.DiagnosticSeverity.Error
+      );
+      diagnostic.code = validationResponse.messageType;
+      diagnostic.source = this.source;
+
+      diagnostics.push(diagnostic);
+    }
+
+    this.diagnosticCollection.set(document.uri, diagnostics);
+  }
+
+  private async validateBPMN(serviceURL: URL, documents: 
vscode.TextDocument[]): Promise<void> {
+    for (const document of documents) {
+      try {
+        const validationResponses: BPMNValidationResponse[] = await 
JITCommands.validateBPMN(serviceURL, [document]);
+        this.createBPMNDiagnostics(document, validationResponses);
+      } catch (error) {
+        vscode.window.showErrorMessage("Validate BPMN error: " + 
error.message);
+      }
+    }
+  }
+
+  private async validateDMN(serviceURL: URL, documents: 
vscode.TextDocument[]): Promise<void> {
+    for (const document of documents) {
+      try {
+        const validationResponses: DMNValidationResponse[] = await 
JITCommands.validateDMN(serviceURL, [document]);
+        this.createDMNDiagnostics(document, validationResponses);
+      } catch (error) {
+        vscode.window.showErrorMessage("Validate DMN error: " + error.message);
+      }
+    }
+  }
+
+  private async validate(serviceURL: URL): Promise<void> {
+    const bpmnFiles: vscode.TextDocument[] = await 
KIEFileWatcher.findOpenBPMNFiles();
+    const dmnFiles: vscode.TextDocument[] = await 
KIEFileWatcher.findOpenDMNFiles();
+    await new Promise((f) => setTimeout(f, 50));

Review Comment:
   Can you please comment on the purpose of this blocking await?



##########
packages/extended-services-vscode-extension/src/local-service-manager.ts:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as childProcess from "child_process";
+import * as path from "path";
+import * as vscode from "vscode";
+
+export class LocalServiceManager {
+  readonly startLocalServiceCommandUID: string = 
"extended-services-vscode-extension.startLocalService";
+  readonly stopLocalServiceCommandUID: string = 
"extended-services-vscode-extension.stopLocalService";
+
+  private readonly relativePath: string = "/dist-dev/extended-services-java";

Review Comment:
   We shouldn't be using the `dist-dev` directory in production code.



##########
packages/extended-services-vscode-extension/src/local-service-manager.ts:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as childProcess from "child_process";
+import * as path from "path";
+import * as vscode from "vscode";
+
+export class LocalServiceManager {

Review Comment:
   Why not `LocalExtendedServicesManager`?



##########
packages/extended-services-vscode-extension/src/jit-executor/responses.ts:
##########
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import * as vscode from "vscode";
+
+export interface BPMNValidationResponse {
+  uri: vscode.Uri;
+  processID: string;
+  name: string;
+  error: string;
+}
+
+export interface DMNValidationResponse {
+  severity: string;
+  message: string;
+  messageType: string;
+  sourceId: string;
+  level: string;
+}
+
+export interface PingResponse {
+  version: string;
+  started: boolean;
+}
+
+export class BPMNValidationResponseParser {
+  public static parse(jsonResponse: string[]): BPMNValidationResponse[] {
+    if (jsonResponse.length > 0) {
+      return jsonResponse.map((response) => {
+        const uriMarker = "Uri: ";
+        const processIdMarker = " - Process id: ";
+        const nameMarker = " - name : ";
+        const errorMarker = " - error : ";

Review Comment:
   Those can all be constants.



##########
packages/extended-services-vscode-extension/src/watchers/configurations/configuration.ts:
##########
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+
+export class Configuration {
+  static readonly autoRunConfigurationID: string = 
"extendedServices.enableAutorun";
+  static readonly serviceURLConfigurationID: string = 
"extendedServices.serviceURL";
+  static readonly connectionHeartbeatIntervalConfigurationID: string = 
"extendedServices.connectionHeartbeatInterval";
+
+  readonly autoRun: boolean;
+  readonly serviceURL: URL;
+  readonly connectionHeartbeatInterval: number;

Review Comment:
   Always a good idea to make the unit clear here, so:
   
   ```suggestion
     readonly connectionHeartbeatIntervalInMs: number;
   ```



##########
packages/extended-services-vscode-extension/src/jit-executor/jit-commands.ts:
##########
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import {
+  BPMNValidationResponse,
+  BPMNValidationResponseParser,
+  DMNValidationResponse,
+  DMNValidationResponseParser,
+  PingResponse,
+} from "./responses";
+import { KIEValidateBodyPayload, KIEValidateResourcePayload } from 
"./payloads";
+
+export class JITCommands {
+  public static async ping(serviceURL: URL): Promise<PingResponse> {
+    const url = new URL("/ping", serviceURL);
+
+    try {
+      const response = await fetch(url.toString());
+      const responseData = (await response.json()) as PingResponse;
+      return responseData;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Ping request: ", 
error.message);
+      return {
+        started: false,
+        version: "undefined",
+      };
+    }
+  }
+
+  public static async validateBPMN(
+    serviceURL: URL,
+    documents: vscode.TextDocument[]
+  ): Promise<BPMNValidationResponse[]> {
+    const url = new URL("/jitbpmn/validate", serviceURL);
+
+    try {
+      const response = await fetch(url.toString(), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JITCommands.buildBodyPayload(documents),
+      });
+
+      const responseData: string[] = (await response.json()) as string[];
+      const validationResponses: BPMNValidationResponse[] = 
BPMNValidationResponseParser.parse(responseData);
+      return validationResponses;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Validate BPMN 
request: ", error.message);
+      throw error;
+    }
+  }
+
+  public static async validateDMN(serviceURL: URL, documents: 
vscode.TextDocument[]): Promise<DMNValidationResponse[]> {
+    const url = new URL("/jitdmn/validate", serviceURL);
+
+    try {
+      const response = await fetch(url.toString(), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JITCommands.buildBodyPayload(documents),
+      });
+
+      const responseData: any = await response.json();
+      const validationResponses: DMNValidationResponse[] = 
DMNValidationResponseParser.parse(responseData);
+      return validationResponses;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Validate DMN 
request: ", error.message);
+      throw error;
+    }
+  }
+
+  private static buildBodyPayload(documents: vscode.TextDocument[]): string {
+    const bodyPayload: KIEValidateBodyPayload = {
+      mainURI: "VS Code KIE files",
+      resources: [],
+    };
+
+    for (const document of documents) {
+      const resourcePayload: KIEValidateResourcePayload = {
+        content: document.getText(),
+        URI: document.fileName,
+      };
+      bodyPayload.resources.push(resourcePayload);
+    }
+
+    try {
+      return JSON.stringify(bodyPayload);
+    } catch (error) {
+      vscode.window.showErrorMessage("Error building body payload: ", 
error.message);
+      return "";

Review Comment:
   Is this a good idea?



##########
packages/extended-services-vscode-extension/src/extension/extension-main.ts:
##########
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import { Configuration } from "../watchers/configurations/configuration";
+import { ConfigurationWatcher } from 
"../watchers/configurations/configuration-watcher";
+import { ConnectionManager } from "../connection-manager";
+import { KIEFileWatcher } from "../watchers/kie-files/kie-file-watcher";
+import { LocalServiceManager } from "../local-service-manager";
+import { ValidationHelper } from "../validation-helper";
+
+const connectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.connectExtendedServices";
+const disconnectExtendedServicesCommandUID: string = 
"extended-services-vscode-extension.disconnectExtendedServices";
+const connectedEnablamentUID: string = 
"extended-services-vscode-extension.connected";
+
+let connectExtendedServicesCommand: vscode.Disposable;
+let disconnectExtendedServicesCommand: vscode.Disposable;
+
+let kieFileWatcher: KIEFileWatcher;
+let configurationWatcher: ConfigurationWatcher;
+let connectionManager: ConnectionManager;
+let localServiceManager: LocalServiceManager;
+let validationHelper: ValidationHelper;
+let statusBarItem: vscode.StatusBarItem;
+let userDisconnected: boolean;
+let connected: boolean;
+
+function connectExtendedServices(): void {
+  userDisconnected = false;
+  const configuration = Configuration.fetchConfiguration();
+  if (configuration) {
+    if (configuration.autoRun) {
+      
vscode.commands.executeCommand(localServiceManager.startLocalServiceCommandUID, 
configuration.serviceURL);
+    } else {
+      vscode.commands.executeCommand(
+        connectionManager.startConnectionHeartbeatCommandUID,
+        configuration.serviceURL,
+        configuration.connectionHeartbeatInterval
+      );
+    }
+  }
+}
+
+function disconnectExtendedServices(): void {
+  userDisconnected = true;
+  const configuration: Configuration | undefined = 
Configuration.fetchConfiguration();
+  if (configuration && configuration.autoRun) {
+    
vscode.commands.executeCommand(localServiceManager.stopLocalServiceCommandUID);
+  } else {
+    
vscode.commands.executeCommand(connectionManager.stopConnectionHeartbeatCommandUID);
+  }
+}
+
+function initializeCommands(context: vscode.ExtensionContext): void {
+  const connectExtendedServicesCommandHandler = () => {
+    connectExtendedServices();
+  };
+
+  const disconnectExtendedServicesCommandHandler = () => {
+    disconnectExtendedServices();
+  };
+
+  connectExtendedServicesCommand = vscode.commands.registerCommand(
+    connectExtendedServicesCommandUID,
+    connectExtendedServicesCommandHandler
+  );
+
+  disconnectExtendedServicesCommand = vscode.commands.registerCommand(
+    disconnectExtendedServicesCommandUID,
+    disconnectExtendedServicesCommandHandler
+  );
+
+  context.subscriptions.push(connectExtendedServicesCommand);
+  context.subscriptions.push(disconnectExtendedServicesCommand);
+}
+
+export function activate(context: vscode.ExtensionContext): void {
+  vscode.commands.executeCommand("setContext", connectedEnablamentUID, false);
+  userDisconnected = false;
+  connected = false;
+
+  statusBarItem = 
vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
+  statusBarItem.show();
+  context.subscriptions.push(statusBarItem);
+
+  kieFileWatcher = new KIEFileWatcher();
+  configurationWatcher = new ConfigurationWatcher();
+  localServiceManager = new LocalServiceManager(context);
+  connectionManager = new ConnectionManager(context);
+  validationHelper = new ValidationHelper(context);
+
+  initializeCommands(context);
+
+  configurationWatcher.subscribeSettingsChanged(() => {
+    if (!userDisconnected && connected) {
+      const configuration: Configuration | undefined = 
Configuration.fetchConfiguration();
+
+      if (configuration && configuration.autoRun) {
+        
vscode.commands.executeCommand(localServiceManager.stopLocalServiceCommandUID);
+      } else {
+        
vscode.commands.executeCommand(connectionManager.stopConnectionHeartbeatCommandUID);
+      }
+
+      if (configuration) {
+        if (configuration.autoRun) {
+          
vscode.commands.executeCommand(localServiceManager.startLocalServiceCommandUID, 
configuration.serviceURL);
+        } else {
+          vscode.commands.executeCommand(
+            connectionManager.startConnectionHeartbeatCommandUID,
+            configuration.serviceURL,
+            configuration.connectionHeartbeatInterval
+          );
+        }
+      }
+    }

Review Comment:
   IMHO there's a lot of nested branches here. I always prefer to use guard 
clauses with `throw`s for exceptional cases. Helps catch errors and prevent the 
system from failing silently.



##########
packages/extended-services-vscode-extension/src/local-service-manager.ts:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as childProcess from "child_process";
+import * as path from "path";
+import * as vscode from "vscode";
+
+export class LocalServiceManager {
+  readonly startLocalServiceCommandUID: string = 
"extended-services-vscode-extension.startLocalService";
+  readonly stopLocalServiceCommandUID: string = 
"extended-services-vscode-extension.stopLocalService";
+
+  private readonly relativePath: string = "/dist-dev/extended-services-java";

Review Comment:
   Also, this variable is named `relativePath` and starts with a `/`..



##########
packages/extended-services-vscode-extension/src/watchers/configurations/configuration.ts:
##########
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+
+export class Configuration {
+  static readonly autoRunConfigurationID: string = 
"extendedServices.enableAutorun";
+  static readonly serviceURLConfigurationID: string = 
"extendedServices.serviceURL";
+  static readonly connectionHeartbeatIntervalConfigurationID: string = 
"extendedServices.connectionHeartbeatInterval";
+
+  readonly autoRun: boolean;
+  readonly serviceURL: URL;

Review Comment:
   ```suggestion
     readonly extendedServicesUrl: URL;
   ```
   
   ?



##########
packages/extended-services-vscode-extension/src/jit-executor/jit-commands.ts:
##########
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import {
+  BPMNValidationResponse,
+  BPMNValidationResponseParser,
+  DMNValidationResponse,
+  DMNValidationResponseParser,
+  PingResponse,
+} from "./responses";
+import { KIEValidateBodyPayload, KIEValidateResourcePayload } from 
"./payloads";
+
+export class JITCommands {

Review Comment:
   ```suggestion
   export class ExtendedServicesClient {
   ```



##########
packages/extended-services-vscode-extension/src/jit-executor/payloads.ts:
##########


Review Comment:
   I think `requests` would be a better name for it, no? :D



##########
packages/extended-services-vscode-extension/src/validation-helper.ts:
##########


Review Comment:
   I'm not a big fan of "helper", "util", "common" terminology... My experience 
tells me those easily become catch-all places with a lot of unrelated stuff, 
creating massive coupling and unmaintainable code. 
   
   In this single-class file, you can already see three mixed responsibilities:
   1. Managing the diagnostic collection of VS Code.
   2. Actually calling Extended Services to validate stuff.
   3. Registering the VS Code commands that will handle the validation.
   
   Please do restructure to reduce coupling.



##########
packages/extended-services-vscode-extension/src/jit-executor/jit-commands.ts:
##########
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import * as vscode from "vscode";
+import {
+  BPMNValidationResponse,
+  BPMNValidationResponseParser,
+  DMNValidationResponse,
+  DMNValidationResponseParser,
+  PingResponse,
+} from "./responses";
+import { KIEValidateBodyPayload, KIEValidateResourcePayload } from 
"./payloads";
+
+export class JITCommands {
+  public static async ping(serviceURL: URL): Promise<PingResponse> {
+    const url = new URL("/ping", serviceURL);
+
+    try {
+      const response = await fetch(url.toString());
+      const responseData = (await response.json()) as PingResponse;
+      return responseData;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Ping request: ", 
error.message);
+      return {
+        started: false,
+        version: "undefined",
+      };
+    }
+  }
+
+  public static async validateBPMN(
+    serviceURL: URL,
+    documents: vscode.TextDocument[]
+  ): Promise<BPMNValidationResponse[]> {
+    const url = new URL("/jitbpmn/validate", serviceURL);
+
+    try {
+      const response = await fetch(url.toString(), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JITCommands.buildBodyPayload(documents),
+      });
+
+      const responseData: string[] = (await response.json()) as string[];
+      const validationResponses: BPMNValidationResponse[] = 
BPMNValidationResponseParser.parse(responseData);
+      return validationResponses;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Validate BPMN 
request: ", error.message);
+      throw error;
+    }
+  }
+
+  public static async validateDMN(serviceURL: URL, documents: 
vscode.TextDocument[]): Promise<DMNValidationResponse[]> {
+    const url = new URL("/jitdmn/validate", serviceURL);
+
+    try {
+      const response = await fetch(url.toString(), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JITCommands.buildBodyPayload(documents),
+      });
+
+      const responseData: any = await response.json();
+      const validationResponses: DMNValidationResponse[] = 
DMNValidationResponseParser.parse(responseData);
+      return validationResponses;
+    } catch (error) {
+      vscode.window.showErrorMessage("Error at JIT-Commands Validate DMN 
request: ", error.message);
+      throw error;
+    }
+  }
+
+  private static buildBodyPayload(documents: vscode.TextDocument[]): string {
+    const bodyPayload: KIEValidateBodyPayload = {
+      mainURI: "VS Code KIE files",
+      resources: [],
+    };
+
+    for (const document of documents) {
+      const resourcePayload: KIEValidateResourcePayload = {
+        content: document.getText(),
+        URI: document.fileName,
+      };
+      bodyPayload.resources.push(resourcePayload);
+    }

Review Comment:
   ```suggestion
       const bodyPayload: KIEValidateBodyPayload = {
         mainURI: "VS Code KIE files",
         resources: documents.map(document => ({
           content: document.getText(),
           URI: document.fileName,
         })),
       };
   ```
   
   ?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to