diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java index 1ebcb73b0..e6c494c13 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java @@ -160,12 +160,7 @@ public class SpringBootApp { public String getJavaCommand() throws IOException { Properties props = this.vm.getSystemProperties(); - if (props.contains("sun.java.command")) { - return props.getProperty("sun.java.command"); - } - else { - return null; - } + return (String) props.get("sun.java.command"); } public boolean containsSystemProperty(Object key) throws IOException { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/Change.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/Change.java index 449a05982..41b2f1e58 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/Change.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/Change.java @@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils; import java.util.ArrayList; import java.util.List; +import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean; /** @@ -20,12 +21,19 @@ import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean; */ public class Change { + private final SpringBootApp runningApp; + private List newBeans; private List deletedBeans; - public Change() { + public Change(SpringBootApp runningApp) { + this.runningApp = runningApp; } + public SpringBootApp getRunningApp() { + return runningApp; + } + public List getNewBeans() { return newBeans; } @@ -49,5 +57,5 @@ public class Change { newBeans.add(bean); } - + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeDetectionHistory.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeDetectionHistory.java index 6f79ddcc0..ca3109e1a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeDetectionHistory.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeDetectionHistory.java @@ -10,8 +10,12 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; @@ -26,26 +30,97 @@ public class ChangeDetectionHistory { this.changeHistory = new HashMap<>(); } - public Change checkForChanges(SpringBootApp app) { - String virtualID = getVirtualAppID(app); + public Change[] checkForChanges(SpringBootApp[] runningApps) { + List result = null; - if (!changeHistory.containsKey(virtualID)) { - ChangeHistory appHistory = new ChangeHistory(virtualID); - changeHistory.put(virtualID, appHistory); + for (SpringBootApp runningApp : runningApps) { + String virtualID = getVirtualAppID(runningApp); + + if (changeHistory.containsKey(virtualID)) { + // the standard case + ChangeHistory appHistory = changeHistory.get(virtualID); + appHistory.updateProcess(runningApp); + + Change change = appHistory.checkForUpdates(); + if (change != null) { + if (result == null) { + result = new ArrayList<>(); + } + result.add(change); + } + } + else { + String oldAppID = getOldApp(runningApp, runningApps); + if (oldAppID != null) { + ChangeHistory oldHistory = changeHistory.remove(oldAppID); + oldHistory.updateProcess(runningApp); + changeHistory.put(virtualID, oldHistory); + + Change change = oldHistory.checkForUpdates(); + if (change != null) { + if (result == null) { + result = new ArrayList<>(); + } + result.add(change); + } + } + else { + ChangeHistory newHistory = new ChangeHistory(); + newHistory.updateProcess(runningApp); + changeHistory.put(virtualID, newHistory); + + newHistory.checkForUpdates(); + } + } } - ChangeHistory appHistory = changeHistory.get(virtualID); - appHistory.updateProcess(app); - - Change result = appHistory.checkForUpdates(); - return result; + if (result != null) { + return (Change[]) result.toArray(new Change[result.size()]); + } + else { + return null; + } } private String getVirtualAppID(SpringBootApp app) { - // TODO: this needs a lot more work to make this a real VIRTUAL ID which detects the same app - // running across different app restarts, so the process ID is not the best way to do this (just - // a temporary solution) return app.getProcessID(); } + private String getOldApp(SpringBootApp app, SpringBootApp[] allApps) { + Set histories = this.changeHistory.keySet(); + + try { + String commandLine = app.getJavaCommand(); + String[] classpath = app.getClasspath(); + + for (String oldProcessID : histories) { + if (this.changeHistory.get(oldProcessID).matchesProcess(commandLine, classpath) + && processNotRunningAnymore(oldProcessID, allApps)) { + return oldProcessID; + } + } + } + catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + private boolean processNotRunningAnymore(String oldProcessID, SpringBootApp[] allApps) { + try { + for (SpringBootApp app : allApps) { + String id = getVirtualAppID(app); + if (id != null && id.equals(oldProcessID)) { + return false; + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + + return true; + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeHistory.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeHistory.java index 22699a4c7..ff20f9234 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeHistory.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ChangeHistory.java @@ -10,7 +10,9 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -27,23 +29,38 @@ public class ChangeHistory { private static final List EMPTY_BEANS_LIST = new ArrayList<>(0); - private final String virtualAppID; - - private SpringBootApp runningProcess; + private SpringBootApp associatedProcess; + private String associatedProcessCommand; + private String[] associatedProcessClasspath; + private LiveBeansModel lastBeans; - public ChangeHistory(String virtualAppID) { - this.virtualAppID = virtualAppID; + public ChangeHistory() { } public void updateProcess(SpringBootApp app) { - this.runningProcess = app; + if (this.associatedProcess != app) { + this.associatedProcess = app; + + try { + this.associatedProcessCommand = app.getJavaCommand(); + this.associatedProcessClasspath = app.getClasspath(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + } + + public boolean matchesProcess(String commandLine, String[] classpath) { + return this.associatedProcessCommand != null && this.associatedProcessCommand.equals(commandLine) + && this.associatedProcessClasspath != null && Arrays.deepEquals(this.associatedProcessClasspath, classpath); } public Change checkForUpdates() { Change result = null; - LiveBeansModel currentBeans = this.runningProcess.getBeans(); + LiveBeansModel currentBeans = this.associatedProcess.getBeans(); if (!currentBeans.isEmpty()) { if (lastBeans == null) { @@ -87,7 +104,7 @@ public class ChangeHistory { if (!contains(currentBeans, bean)) { if (result == null) { - result = new Change(); + result = new Change(associatedProcess); } result.addDeletedBean(bean); @@ -98,7 +115,7 @@ public class ChangeHistory { if (!contains(previousBeans, bean)) { if (result == null) { - result = new Change(); + result = new Change(associatedProcess); } result.addNewBean(bean); @@ -111,7 +128,7 @@ public class ChangeHistory { private boolean contains(List beans, LiveBean bean) { for (LiveBean beansFromList : beans) { if (StringUtils.equals(beansFromList.getId(), bean.getId()) - && StringUtils.equals(beansFromList.getType(), bean.getType()) + && StringUtils.equals(beansFromList.getType(true), bean.getType(true)) && StringUtils.equals(beansFromList.getResource(), bean.getResource())) { return true; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java index 8ecb1a327..c50d43983 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java @@ -135,6 +135,12 @@ public class SpringLiveChangeDetectionWatchdog { if (changeDetectionEnabled) { try { SpringBootApp[] runningBootApps = runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); + Change[] changes = changeHistory.checkForChanges(runningBootApps); + if (changes != null && changes.length > 0) { + for (Change change : changes) { + publishDetectedChange(change); + } + } for (SpringBootApp app : runningBootApps) { updateApp(app); } @@ -145,16 +151,12 @@ public class SpringLiveChangeDetectionWatchdog { } private void updateApp(SpringBootApp app) { - Change change = changeHistory.checkForChanges(app); - if (change != null) { - publishDetectedChange(change, app); - } } - private void publishDetectedChange(Change change, SpringBootApp app) { + private void publishDetectedChange(Change change) { Map> diagnostics = new HashMap<>(); - IJavaProject[] projects = findProjectsFor(app); + IJavaProject[] projects = findProjectsFor(change.getRunningApp()); List deletedBeans = change.getDeletedBeans(); if (deletedBeans != null) {