diff --git a/src/Constants.ts b/src/Constants.ts index f6a3153..f604e46 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -22,3 +22,9 @@ export enum ServerState { RunningServer = 'runningserver', IdleServer = 'idleserver' } + +export enum PortKind { + Server = 'Server', + Http = 'Http', + Https = 'Https' +} diff --git a/src/Tomcat/TomcatController.ts b/src/Tomcat/TomcatController.ts index 9a71acc..273ee1f 100644 --- a/src/Tomcat/TomcatController.ts +++ b/src/Tomcat/TomcatController.ts @@ -48,7 +48,7 @@ export class TomcatController { if (this._tomcat.deleteServer(tomcatServer)) { const output: vscode.OutputChannel = this.getOutput(tomcatServer); - this._outputChannels.delete(this.getChannelName(tomcatServer)); + this._outputChannels.delete(`Tomcat_${tomcatServer.getName()}`); output.dispose(); } vscode.commands.executeCommand('tomcat.tree.refresh'); @@ -233,7 +233,7 @@ export class TomcatController { } private async getServerUri(serverInfo: TomcatServer, appName?: string): Promise { - const serverPort: string = await Utility.getHttpPort(serverInfo.getServerConfigPath()); + const serverPort: string = await Utility.getPort(serverInfo.getServerConfigPath(), Constants.PortKind.Http); if (!serverPort) { throw new Error('No http port found in server.xml'); } @@ -247,6 +247,10 @@ export class TomcatController { const serverName: string = serverInfo.getName(); let watcher: chokidar.FSWatcher; const serverUri: string = await this.getServerUri(serverInfo, appName); + const serverConfig: string = serverInfo.getServerConfigPath(); + const serverPort: string = await Utility.getPort(serverConfig, Constants.PortKind.Server); + const httpPort: string = await Utility.getPort(serverConfig, Constants.PortKind.Http); + const httpsPort: string = await Utility.getPort(serverConfig, Constants.PortKind.Https); try { if (serverUri) { @@ -260,31 +264,35 @@ export class TomcatController { statusBar.show(); } - watcher = chokidar.watch(serverInfo.getServerConfigPath()); + watcher = chokidar.watch(serverConfig); watcher.on('change', async () => { - const promptString: string = localize('tomcatExt.configChanged', - 'server.xml of running server {0} has been changed. Would you like to restart it?', - serverName); - const item: vscode.MessageItem = await vscode.window.showInformationMessage(promptString, DialogMessage.yes, DialogMessage.no); - if (item === DialogMessage.yes) { - try { - // Need restart tomcat - await this.stopServer(serverInfo); - serverInfo.needRestart = true; - } catch (err) { - console.error(err.toString()); - vscode.window.showErrorMessage(localize('tomcatExt.stopFailure', 'Failed to stop Tomcat Server {0}', serverName)); + if (serverPort !== await Utility.getPort(serverConfig, Constants.PortKind.Server)) { + vscode.window.showErrorMessage(localize('tomcatExt.serverPortChangeError', `Changing the server port of a running server will cause errors, please change it back to ${ serverPort} !`)); + } else if (httpPort !== await Utility.getPort(serverConfig, Constants.PortKind.Http) || + httpsPort !== await Utility.getPort(serverConfig, Constants.PortKind.Https)) { + const promptString: string = localize('tomcatExt.configChanged', + 'server.xml of running server {0} has been changed. Would you like to restart it?', + serverName); + const item: vscode.MessageItem = await vscode.window.showInformationMessage(promptString, DialogMessage.yes, DialogMessage.no); + if (item === DialogMessage.yes) { + try { + // Need restart tomcat + await this.stopServer(serverInfo); + serverInfo.needRestart = true; + } catch (err) { + console.error(err.toString()); + vscode.window.showErrorMessage(localize('tomcatExt.stopFailure', 'Failed to stop Tomcat Server {0}', serverName)); + } } } }); const javaProcess: Promise = Utility.executeCMD(output, 'java', { shell: true }, ...this.getJavaArgs(serverInfo, true)); + this.setStarted(serverInfo, true); this.startDebugSession(serverInfo); - setTimeout(() => this.setStarted(serverInfo, true), 500); await javaProcess; this.setStarted(serverInfo, false); - this.disposeResource(statusBarCommand); - this.disposeResource(statusBar); + this.disposeResources(statusBarCommand, statusBar); watcher.close(); if (serverInfo.needRestart) { serverInfo.needRestart = false; @@ -292,25 +300,20 @@ export class TomcatController { } } catch (err) { this.setStarted(serverInfo, false); - this.disposeResource(statusBarCommand); - this.disposeResource(statusBar); + this.disposeResources(statusBarCommand, statusBar); if (watcher) { watcher.close(); } throw new Error(err.toString()); } } - private disposeResource(resource: vscode.Disposable | undefined): void { - if (resource) { - resource.dispose(); + private disposeResources(...resources: vscode.Disposable[]): void { + if (resources) { + resources.forEach((item: vscode.Disposable) => item.dispose()); } } - private getChannelName(serverInfo: TomcatServer): string { - return `Tomcat_${serverInfo.getName()}`; - } - private getOutput(serverInfo: TomcatServer): vscode.OutputChannel { - const channelName: string = this.getChannelName(serverInfo); + const channelName: string = `Tomcat_${serverInfo.getName()}`; let output: vscode.OutputChannel = this._outputChannels.get(channelName); if (!output) { output = vscode.window.createOutputChannel(channelName); diff --git a/src/TomcatServerTree.ts b/src/TomcatServerTree.ts index c8487d0..7b38378 100644 --- a/src/TomcatServerTree.ts +++ b/src/TomcatServerTree.ts @@ -54,6 +54,10 @@ export class TomcatSeverTreeProvider implements vscode.TreeDataProvider { const treeItem: TomcatTreeItem = new TomcatTreeItem(this._context, element); + /* qisun: checking http port is not a valid way to detect the server running or not + // update the logic when finding a proper way to check the server real state + // currently behavior is ignoring the server state outside vscode + // and always stop servers when exiting vscode try { const port: string = await Utility.getHttpPort(treeItem.serverConfig); // tslint:disable-next-line:no-any no-http-string @@ -62,6 +66,7 @@ export class TomcatSeverTreeProvider implements vscode.TreeDataProvider | undefined { + export function getTempStoragePath(): string { + const chars: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + let result: string = ''; + for (let i: number = 0; i < 5; i += 1) { + // tslint:disable-next-line:insecure-random + const idx: number = Math.floor(chars.length * Math.random()); + result += chars[idx]; + } + return path.resolve(os.tmpdir(), `vscodetomcat_${result}`); + } + + export async function getPort(serverXml: string, kind: Constants.PortKind): Promise { if (!await fse.pathExists(serverXml)) { throw new Error(localize('tomcatExt.noserver', 'No tomcat server.')); } @@ -68,15 +80,22 @@ export namespace Utility { try { /* tslint:disable:no-any */ const jsonObj: any = await parseXml(xml); - port = jsonObj.Server.Service.find((item: any) => item.$.name === Constants.CATALINA).Connector.find((item: any) => - (item.$.protocol === undefined || item.$.protocol.startsWith(Constants.HTTP))).$.port; + if (kind === Constants.PortKind.Server) { + port = jsonObj.Server.$.port; + } else if (kind === Constants.PortKind.Http) { + port = jsonObj.Server.Service.find((item: any) => item.$.name === Constants.CATALINA).Connector.find((item: any) => + (item.$.protocol === undefined || item.$.protocol.startsWith(Constants.HTTP))).$.port; + } else if (kind === Constants.PortKind.Https) { + port = jsonObj.Server.Service.find((item: any) => item.$.name === Constants.CATALINA).Connector.find((item: any) => + (item.$.SSLEnabled.toLowerCase() === 'true')).$.port; + } } catch (err) { port = undefined; } return port; }/* tslint:enable:no-any */ - // tslint:disable-next-line:no-any + /* tslint:disable:no-any */ async function parseXml(xml: string): Promise { return new Promise((resolve: (obj: {}) => void, reject: (e: Error) => void): void => { xml2js.parseString(xml, { explicitArray: true }, (err: Error, res: {}) => { @@ -86,5 +105,5 @@ export namespace Utility { return resolve(res); }); }); - } + }/* tslint:enable:no-any */ } diff --git a/src/extension.ts b/src/extension.ts index 2ff514b..c4b15f8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,7 +2,6 @@ import * as child_process from "child_process"; import * as fse from "fs-extra"; -import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; import { MessageItem } from "vscode"; @@ -17,7 +16,7 @@ import { Utility } from "./Utility"; export function activate(context: vscode.ExtensionContext): void { let storagePath: string = context.storagePath; if (!storagePath) { - storagePath = path.resolve(os.tmpdir(), `vscodetomcat_${makeRandomHexString(5)}`); + storagePath = Utility.getTempStoragePath(); } const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('Tomcat'); const tomcatData: Tomcat = new Tomcat(storagePath); @@ -196,16 +195,5 @@ async function runOnTomcat(tomcatController: TomcatController, debug: boolean, u await tomcatController.runOnServer(server, packagePath, debug); } -function makeRandomHexString(length: number): string { - const chars: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; - let result: string = ''; - for (let i: number = 0; i < length; i += 1) { - // tslint:disable-next-line:insecure-random - const idx: number = Math.floor(chars.length * Math.random()); - result += chars[idx]; - } - return result; -} - // tslint:disable-next-line:no-empty export function deactivate(): void {} diff --git a/test/utility.test.ts b/test/utility.test.ts index 69f6505..9d25ed0 100644 --- a/test/utility.test.ts +++ b/test/utility.test.ts @@ -1,5 +1,6 @@ import * as assert from "assert"; import * as path from "path"; +import * as Constants from "../src/Constants"; import { TomcatServer } from "../src/Tomcat/TomcatServer"; import { Utility } from "../src/Utility"; @@ -15,7 +16,7 @@ suite('utility tests', () => { test('getPort', async () => { try { const filePath: string = path.resolve(__dirname, '../../testResources/server.xml'); - const port: string = await Utility.getHttpPort(filePath); + const port: string = await Utility.getPort(filePath, Constants.PortKind.Http); assert.equal(port, '8081'); } catch (error) { assert.fail('no error', 'error');