diff --git a/src/commands/stream-debug-attach-command.ts b/src/commands/stream-debug-attach-command.ts index d88682c..2df11d7 100644 --- a/src/commands/stream-debug-attach-command.ts +++ b/src/commands/stream-debug-attach-command.ts @@ -18,21 +18,24 @@ import { Command } from '@pivotal-tools/vscode-extension-di'; import { COMMAND_SCDF_STREAM_DEBUG_ATTACH } from '../extension-globals'; import { TYPES } from '../types'; import { InstanceNode } from '../explorer/models/instance-node'; -import { StreamDebugManager } from '../debug/stream-debug-manager'; +import { DebugManager } from '../debug/debug-manager'; @injectable() export class StreamDebugAttachCommand implements Command { constructor( - @inject(TYPES.StreamDebugManager) private streamDebugManager: StreamDebugManager + @inject(TYPES.DebugManager) private debugManager: DebugManager ) {} get id() { return COMMAND_SCDF_STREAM_DEBUG_ATTACH; } - async execute(args: InstanceNode) { - const debugConfiguration = await this.streamDebugManager.streamAppInstanceDebugConfiguration(args); - this.streamDebugManager.launchDebug([debugConfiguration]); + async execute(node: InstanceNode) { + const streamName = node.streamName; + const appName = node.appName; + const serverRegistration = node.registration; + const debugHandler = this.debugManager.getStreamDebugHandler(streamName, appName, serverRegistration); + debugHandler.attach(); } } diff --git a/src/commands/tasks-debug-attach-command.ts b/src/commands/tasks-debug-attach-command.ts index d5e61f0..7cf696e 100644 --- a/src/commands/tasks-debug-attach-command.ts +++ b/src/commands/tasks-debug-attach-command.ts @@ -17,22 +17,24 @@ import { injectable, inject } from 'inversify'; import { Command } from '@pivotal-tools/vscode-extension-di'; import { COMMAND_SCDF_TASKS_DEBUG_ATTACH } from '../extension-globals'; import { TYPES } from '../types'; -import { StreamDebugManager } from '../debug/stream-debug-manager'; import { ExecutionNode } from '../explorer/models/execution-node'; +import { DebugManager } from '../debug/debug-manager'; @injectable() export class TasksDebugAttachCommand implements Command { constructor( - @inject(TYPES.StreamDebugManager) private streamDebugManager: StreamDebugManager + @inject(TYPES.DebugManager) private debugManager: DebugManager ) {} get id() { return COMMAND_SCDF_TASKS_DEBUG_ATTACH; } - async execute(args: ExecutionNode) { - const debugConfiguration = await this.streamDebugManager.taskExecutionNodeDebugConfiguration(args); - this.streamDebugManager.launchDebug([debugConfiguration]); + async execute(node: ExecutionNode) { + const executionId = node.executionId; + const serverRegistration = node.registration; + const debugHandler = this.debugManager.getTaskDebugHandler(executionId, serverRegistration); + debugHandler.attach(); } } diff --git a/src/debug/debug-handler.ts b/src/debug/debug-handler.ts new file mode 100644 index 0000000..517c80b --- /dev/null +++ b/src/debug/debug-handler.ts @@ -0,0 +1,80 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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 + * + * https://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 { DebugConfiguration } from 'vscode'; +import { ServerRegistration } from '../service/server-registration-manager'; +import { DebugProvider } from './debug-provider'; +import { ScdfModel } from '../service/scdf-model'; + +export interface DebugHandler { + + attach(): Promise; + +} + +export class DefaultStreamDebugHandler implements DebugHandler { + + constructor( + private serverRegistration: ServerRegistration, + private streamName: string, + private appName: string, + private debugProvider: DebugProvider + ) {} + + public async attach(): Promise { + const model = new ScdfModel(this.serverRegistration); + const deployment = model.getStreamDeployment(this.streamName); + const entry = await deployment; + const name = `Debug (Attach) - ${this.streamName} ${this.appName}`; + const port = +entry.deploymentProperties.log['spring.cloud.deployer.local.debug-port']; + + const config: DebugConfiguration = { + type: 'java', + name: name, + request: 'attach', + hostName: "localhost", + port: port + }; + + this.debugProvider.startDebug(config); + } +} + +export class DefaultTaskDebugHandler implements DebugHandler { + + constructor( + private serverRegistration: ServerRegistration, + private executionId: number, + private debugProvider: DebugProvider + ) {} + + public async attach(): Promise { + const model = new ScdfModel(this.serverRegistration); + const execution = await model.getTaskExecution(this.executionId); + const name = `Debug (Attach) - ${execution.taskName} ${this.executionId}`; + const port = +execution.deploymentProperties['deployer.timestamp.local.debug-port']; + + const config: DebugConfiguration = { + type: 'java', + name: name, + request: 'attach', + hostName: "localhost", + port: port + }; + + this.debugProvider.startDebug(config); + } +} diff --git a/src/debug/debug-manager.ts b/src/debug/debug-manager.ts new file mode 100644 index 0000000..30315bd --- /dev/null +++ b/src/debug/debug-manager.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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 + * + * https://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 { injectable, multiInject } from 'inversify'; +import { ServerRegistration } from '../service/server-registration-manager'; +import { DefaultStreamDebugHandler, DebugHandler, DefaultTaskDebugHandler } from './debug-handler'; +import { TYPES } from '../types'; +import { DebugProvider } from './debug-provider'; + +@injectable() +export class DebugManager { + + constructor( + @multiInject(TYPES.DebugProvider) private debugProviders: DebugProvider[] + ) {} + + public getStreamDebugHandler( + streamName: string, + appName: string, + serverRegistration: ServerRegistration + ): DebugHandler { + // find debug provider which supports our env + const debugProvider = this.debugProviders[0]; + return new DefaultStreamDebugHandler(serverRegistration, streamName, appName, debugProvider); + } + + public getTaskDebugHandler( + executionId: number, + serverRegistration: ServerRegistration + ): DebugHandler { + // find debug provider which supports our env + const debugProvider = this.debugProviders[0]; + return new DefaultTaskDebugHandler(serverRegistration, executionId, debugProvider); + } +} diff --git a/src/debug/debug-provider.ts b/src/debug/debug-provider.ts new file mode 100644 index 0000000..8c6d1fd --- /dev/null +++ b/src/debug/debug-provider.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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 + * + * https://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 { DebugConfiguration, debug, WorkspaceFolder } from 'vscode'; +import { injectable } from 'inversify'; + +export interface DebugProvider { + + getDebugType(): string; + + hasDebugger(): Promise; + + startDebug(config: DebugConfiguration): Promise; +} + +@injectable() +export class LocalDebugProvider implements DebugProvider { + + public getDebugType(): string { + return 'java'; + } + + public async hasDebugger(): Promise { + return true; + } + + public async startDebug(config: DebugConfiguration): Promise { + const folder: WorkspaceFolder | undefined = undefined; + const started = await debug.startDebugging(folder, config); + return started; + } +} diff --git a/src/debug/di.config.ts b/src/debug/di.config.ts new file mode 100644 index 0000000..690a85a --- /dev/null +++ b/src/debug/di.config.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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 + * + * https://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 { ContainerModule } from 'inversify'; +import { DebugProvider, LocalDebugProvider } from './debug-provider'; +import { TYPES } from '../types'; +import { DebugManager } from './debug-manager'; + +const debugContainerModule = new ContainerModule((bind) => { + bind(TYPES.DebugProvider).to(LocalDebugProvider); + bind(TYPES.DebugManager).to(DebugManager).inSingletonScope(); +}); +export default debugContainerModule; diff --git a/src/debug/stream-debug-manager.ts b/src/debug/stream-debug-manager.ts deleted file mode 100644 index ce3f4eb..0000000 --- a/src/debug/stream-debug-manager.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019 the original author or authors. - * - * 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 - * - * https://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 { DebugConfiguration, debug } from 'vscode'; -import { injectable } from 'inversify'; -import { InstanceNode } from '../explorer/models/instance-node'; -import { ScdfModel } from '../service/scdf-model'; -import { ExecutionNode } from '../explorer/models/execution-node'; - -@injectable() -export class StreamDebugManager { - - public async streamAppInstanceDebugConfiguration(streamAppInstance: InstanceNode): Promise { - const model = new ScdfModel(streamAppInstance.registration); - const deployment = model.getStreamDeployment(streamAppInstance.streamName); - const entry = await deployment; - const name = `Debug (Attach) - ${streamAppInstance.streamName} ${streamAppInstance.appName}`; - const port = +entry.deploymentProperties.log['spring.cloud.deployer.local.debug-port']; - const config: DebugConfiguration = { - type: 'java', - name: name, - request: 'attach', - hostName: "localhost", - port: port - }; - return config; - } - - public async taskExecutionNodeDebugConfiguration(executedTaskInstance: ExecutionNode): Promise { - const model = new ScdfModel(executedTaskInstance.registration); - // const deployment = model.getStreamDeployment(executedTaskInstance.taskName); - // const entry = await deployment; - const name = `Debug (Attach) - ${executedTaskInstance.taskName} ${executedTaskInstance.externalExecutionId}`; - // const port = +entry.deploymentProperties.log['spring.cloud.deployer.local.debug-port']; - // TODO: just hardcode until we get these exposed from dataflow - const port = 20100; - const config: DebugConfiguration = { - type: 'java', - name: name, - request: 'attach', - hostName: "localhost", - port: port - }; - return config; - } - public launchDebug(configs: DebugConfiguration[]): void { - configs.forEach(config => { - debug.startDebugging(undefined, config); - }); - } -} diff --git a/src/scdf-extension.ts b/src/scdf-extension.ts index c5351eb..f5adcdd 100644 --- a/src/scdf-extension.ts +++ b/src/scdf-extension.ts @@ -23,13 +23,13 @@ import { import { DITYPES, DiExtension } from '@pivotal-tools/vscode-extension-di'; import { TYPES } from './types'; import commandsContainerModule from './commands/di.config'; +import debugContainerModule from './debug/di.config'; import { ScdfLanguageSupport } from './language/scdf-language-support'; import { AppsExplorerProvider } from './explorer/apps-explorer-provider'; import { StreamsExplorerProvider } from './explorer/streams-explorer-provider'; import { TasksExplorerProvider } from './explorer/tasks-explorer-provider'; import { ServerRegistrationStatusBarManagerItem } from './statusbar/server-registration-status-bar-manager-item'; import { ServerRegistrationManager } from './service/server-registration-manager'; -import { StreamDebugManager } from './debug/stream-debug-manager'; import { JobsExplorerProvider } from './explorer/jobs-explorer-provider'; import { CONFIG_SCDF_NOTIFICATION_LOCATION } from './extension-globals'; @@ -47,6 +47,7 @@ export class ScdfExtension extends DiExtension { public onContainer(container: Container): void { super.onContainer(container); + container.load(debugContainerModule); container.load(commandsContainerModule); container.bind(DITYPES.NotificationManagerLocationKey).toConstantValue(CONFIG_SCDF_NOTIFICATION_LOCATION); @@ -65,8 +66,6 @@ export class ScdfExtension extends DiExtension { const serverRegistrationManager = container.get(TYPES.ServerRegistrationManager); container.bind(DITYPES.ExtensionActivateAware).toConstantValue(serverRegistrationManager); - container.bind(TYPES.StreamDebugManager).to(StreamDebugManager).inSingletonScope(); - // to fire build flow container.get(TYPES.AppsExplorerProvider); container.get(TYPES.StreamsExplorerProvider); diff --git a/src/service/scdf-model.ts b/src/service/scdf-model.ts index 4c60908..b213f45 100644 --- a/src/service/scdf-model.ts +++ b/src/service/scdf-model.ts @@ -56,6 +56,7 @@ export interface ScdfTaskExecutionEntry extends BaseEntry { jobExecutionIds: number[]; parentExecutionId: number; startTime: string; + deploymentProperties: DeploymentProperties; taskExecutionStatus: string; taskName: string; } diff --git a/src/types.ts b/src/types.ts index cf6e25b..1b22795 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,5 +20,6 @@ export const TYPES = { TasksExplorerProvider: Symbol('TasksExplorerProvider'), JobsExplorerProvider: Symbol('JobsExplorerProvider'), ServerRegistrationStatusBarManagerItem: Symbol('ServerRegistrationStatusBarManagerItem'), - StreamDebugManager: Symbol('StreamDebugManager') + DebugManager: Symbol('DebugManager'), + DebugProvider: Symbol('DebugProvider') };