process status added, incl. disconnect command

This commit is contained in:
Martin Lippert
2019-09-09 20:31:44 +02:00
parent e4b2a4c430
commit 5902f920bd
10 changed files with 237 additions and 95 deletions

View File

@@ -78,8 +78,6 @@ public class LiveProcessCommandElement extends QuickAccessElement {
@Override
public void execute() {
System.out.println("EXECUTE THE COMMAND !!!");
List<@NonNull LanguageServer> usedLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(serverCapabilities -> true);
if (usedLanguageServers.isEmpty()) {

View File

@@ -49,8 +49,6 @@ public class LiveProcessCommandsQuickAccessProvider implements IQuickAccessCompu
@Override
public QuickAccessElement[] computeElements(String query, IProgressMonitor monitor) {
System.out.println("COMPUTE QUICK ACCESS ELEMENTS !!!");
this.usedLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(serverCapabilities -> true);
if (usedLanguageServers.isEmpty()) {
@@ -65,12 +63,6 @@ public class LiveProcessCommandsQuickAccessProvider implements IQuickAccessCompu
ls.getWorkspaceService().executeCommand(commandParams).thenAcceptAsync(commandResult ->
createCommandItems(res, commandResult))).toArray(CompletableFuture[]::new)).join();
System.out.println("quick access elements computed: " + res.size());
for (QuickAccessElement quickAccessElement : res) {
System.out.println("generated element: " + quickAccessElement.getLabel());
}
return res.toArray(new QuickAccessElement[res.size()]);
}

View File

@@ -61,10 +61,10 @@ public class SpringProcessCommandHandler {
private CompletableFuture<Object> connect(ExecuteCommandParams params) {
String processKey = getProcessKey(params);
if (processKey != null) {
SpringProcessDescriptor[] processes = localProcessConnector.getProcesses();
SpringProcessDescriptor[] processes = localProcessConnector.getProcesses(false, SpringProcessStatus.REGULAR);
for (SpringProcessDescriptor process : processes) {
if (process.getProcessKey().equals(processKey)) {
localProcessConnector.connectLocalProcess(process, false);
localProcessConnector.connectProcess(process);
return CompletableFuture.completedFuture(null);
}
}
@@ -83,6 +83,11 @@ public class SpringProcessCommandHandler {
}
private CompletableFuture<Object> disconnect(ExecuteCommandParams params) {
String processKey = getProcessKey(params);
if (processKey != null) {
connectorService.disconnectProcess(processKey);
}
return CompletableFuture.completedFuture(null);
}
@@ -96,20 +101,26 @@ public class SpringProcessCommandHandler {
for (SpringProcessConnector process : connectedProcesses) {
String processKey = process.getProcessKey();
String label = process.getLabel();
String action = COMMAND_REFRESH;
LiveProcessCommand command = new LiveProcessCommand();
command.setAction(action);
command.setLabel(label);
command.setProcessKey(processKey);
result.add(command);
LiveProcessCommand refreshCommand = new LiveProcessCommand();
refreshCommand.setAction(COMMAND_REFRESH);
refreshCommand.setLabel(label);
refreshCommand.setProcessKey(processKey);
result.add(refreshCommand);
if (localProcessConnector.isLocalProcess(process.getProcessKey())) {
LiveProcessCommand disconnectCommand = new LiveProcessCommand();
disconnectCommand.setAction(COMMAND_DISCONNECT);
disconnectCommand.setLabel(label);
disconnectCommand.setProcessKey(processKey);
result.add(disconnectCommand);
}
alreadyConnected.add(processKey);
}
// other available local processes
SpringProcessDescriptor[] localProcesses = localProcessConnector.getProcesses();
SpringProcessDescriptor[] localProcesses = localProcessConnector.getProcesses(true, SpringProcessStatus.REGULAR);
for (SpringProcessDescriptor localProcess : localProcesses) {
String processKey = localProcess.getProcessKey();
if (!alreadyConnected.contains(processKey)) {

View File

@@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
/**
* @author Martin Lippert
*/
public interface SpringProcessConnectionChangeListener {
void connectionClosed(String processKey);
}

View File

@@ -21,5 +21,8 @@ public interface SpringProcessConnector {
void connect() throws Exception;
void refresh() throws Exception;
void disconnect() throws Exception;
void addConnectorChangeListener(SpringProcessConnectionChangeListener listener);
void removeConnectorChangeListener(SpringProcessConnectionChangeListener listener);
}

View File

@@ -18,6 +18,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,6 +73,7 @@ public class SpringProcessConnectorLocal {
ProjectObserver projectObserver) {
this.projects = Collections.synchronizedCollection(new HashSet<>());
this.processes = Collections.synchronizedSet(new HashSet<>());
this.liveDataProvider = liveDataProvider;
this.processConnectorService = processConnector;
@@ -103,22 +106,26 @@ public class SpringProcessConnectorLocal {
}
}
public SpringProcessDescriptor[] getProcesses() {
if (processes.size() == 0) {
updateProcesses();
}
return (SpringProcessDescriptor[]) processes.toArray(new SpringProcessDescriptor[processes.size()]);
}
public void searchForNewProcesses() {
SpringProcessDescriptor[] newProcesses = updateProcesses();
for (SpringProcessDescriptor descriptor : newProcesses) {
connectLocalProcess(descriptor, true);
}
public boolean isLocalProcess(String processKey) {
return this.processes.stream().anyMatch(process -> processKey.equals(process.getProcessKey()));
}
public SpringProcessDescriptor[] getProcesses(boolean update, SpringProcessStatus status) {
if (update) {
SpringProcessDescriptor[] newProcesses = updateProcesses();
if (newProcesses.length > 0) {
updateStatus(newProcesses);
}
}
if (status != null) {
return processes.stream().filter((process) -> status.equals(process.getStatus())).toArray(SpringProcessDescriptor[]::new);
}
else {
return (SpringProcessDescriptor[]) processes.toArray(new SpringProcessDescriptor[processes.size()]);
}
}
public SpringProcessDescriptor[] updateProcesses() {
List<VirtualMachineDescriptor> currentVms = VirtualMachine.list();
Set<String> currentVMKeys = new HashSet<>();
@@ -159,7 +166,66 @@ public class SpringProcessConnectorLocal {
return (SpringProcessDescriptor[]) newProcesses.toArray(new SpringProcessDescriptor[newProcesses.size()]);
}
public void connectLocalProcess(SpringProcessDescriptor descriptor, boolean checkAutoConnect) {
private void updateStatus(SpringProcessDescriptor[] newProcesses) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (SpringProcessDescriptor newProcess : newProcesses) {
CompletableFuture<SpringProcessStatus> checkStatusFuture = checkStatus(newProcess);
CompletableFuture<Void> result = checkStatusFuture.thenAccept((status) -> newProcess.setStatus(status));
futures.add(result);
}
CompletableFuture<Void> allStatusUpdates = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
try {
allStatusUpdates.get(3, TimeUnit.SECONDS);
}
catch (Exception e) {
log.info("timeout or problem occured while updating the status of the new processes");
}
}
private CompletableFuture<SpringProcessStatus> checkStatus(SpringProcessDescriptor descriptor) {
if (SpringProcessStatus.UNKNOWN.equals(descriptor.getStatus())) {
return CompletableFuture.supplyAsync(() -> {
VirtualMachine vm = null;
try {
vm = VirtualMachine.attach(descriptor.getVm());
boolean ignore = shouldIgnore(descriptor.getVm(), vm);
boolean autoConnect = shouldAutoConnect(descriptor.getVm(), vm);
if (ignore) {
return SpringProcessStatus.IGNORE;
}
else if (autoConnect) {
return SpringProcessStatus.AUTO_CONNECT;
}
else {
return SpringProcessStatus.REGULAR;
}
}
catch (Exception e) {
return SpringProcessStatus.IGNORE;
}
finally {
if (vm != null) {
try {
vm.detach();
}
catch (Exception e) {
log.error("error detaching from vm: " + descriptor.getVm().id(), e);
}
}
}
});
}
return CompletableFuture.completedFuture(SpringProcessStatus.UNKNOWN);
}
public void connectProcess(SpringProcessDescriptor descriptor) {
VirtualMachine vm = null;
VirtualMachineDescriptor vmDescriptor = descriptor.getVm();
@@ -167,10 +233,6 @@ public class SpringProcessConnectorLocal {
String jmxAddress = null;
vm = VirtualMachine.attach(vmDescriptor);
if (checkAutoConnect && !shouldAutoConnectToProcess(vmDescriptor, vm)) {
return;
}
try {
jmxAddress = vm.getAgentProperties().getProperty(LOCAL_CONNECTOR_ADDRESS);
} catch (Exception e) {
@@ -211,37 +273,45 @@ public class SpringProcessConnectorLocal {
}
}
private boolean shouldAutoConnectToProcess(VirtualMachineDescriptor vmDescriptor, VirtualMachine vm) {
return false;
private boolean shouldIgnore(VirtualMachineDescriptor vmDescriptor, VirtualMachine vm) {
try {
String displayName = vmDescriptor.displayName();
if (displayName != null && displayName.startsWith(ECLIPSE_PROCESS_DISPLAY_NAME_PREFIX)) {
log.info("Eclipse process found, do not connect: " + vmDescriptor.id());
return true;
}
Properties systemProperties = vm.getSystemProperties();
Object languageServerIndicatorProperty = systemProperties.get(LANGUAGE_SERVER_PROPERTY);
if (languageServerIndicatorProperty != null) {
log.info("language server process found, do not connect: " + vmDescriptor.id());
return true;
}
}
catch (Exception e) {
return true;
}
// try {
// String displayName = vmDescriptor.displayName();
// if (displayName != null && displayName.startsWith(ECLIPSE_PROCESS_DISPLAY_NAME_PREFIX)) {
// log.info("Eclipse process found, do not connect: " + vmDescriptor.id());
// return false;
// }
//
// Properties systemProperties = vm.getSystemProperties();
//
// Object projectNameProperty = systemProperties.get(SPRING_APP_PROJECT_NAME_PROPERTY);
// if (projectNameProperty instanceof String) {
// log.info("Spring boot process found: " + projectNameProperty);
// return this.projects.contains((String) projectNameProperty);
// }
//
// Object languageServerIndicatorProperty = systemProperties.get(LANGUAGE_SERVER_PROPERTY);
// if (languageServerIndicatorProperty != null) {
// log.info("language server process found, do not connect: " + vmDescriptor.id());
// return false;
// }
//
// }
// catch (Exception e) {
// return false;
// }
//
// // default case:
// return true;
return false;
}
private boolean shouldAutoConnect(VirtualMachineDescriptor vmDescriptor, VirtualMachine vm) {
try {
Properties systemProperties = vm.getSystemProperties();
Object projectNameProperty = systemProperties.get(SPRING_APP_PROJECT_NAME_PROPERTY);
if (projectNameProperty instanceof String) {
log.info("Spring boot process found: " + projectNameProperty);
return this.projects.contains((String) projectNameProperty);
}
}
catch (Exception e) {
return false;
}
return false;
}
private String getProcessID(VirtualMachineDescriptor descriptor) {
@@ -253,5 +323,5 @@ public class SpringProcessConnectorLocal {
int firstSpace = rawName.indexOf(' ');
return firstSpace < 0 ? rawName : rawName.substring(0, firstSpace);
}
}

View File

@@ -10,6 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
@@ -33,6 +36,8 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
private final String host;
private final String port;
private final List<SpringProcessConnectionChangeListener> listeners;
public SpringProcessConnectorOverJMX(SpringProcessLiveDataProvider liveDataProvider, String processKey, String jmxURL,
String urlScheme, String processID, String processName, String host, String port) {
@@ -44,6 +49,8 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
this.processName = processName;
this.host = host;
this.port = port;
this.listeners = new CopyOnWriteArrayList<>();
}
@Override
@@ -103,4 +110,22 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
this.liveDataProvider.remove(processKey);
}
@Override
public void addConnectorChangeListener(SpringProcessConnectionChangeListener listener) {
this.listeners.add(listener);
}
@Override
public void removeConnectorChangeListener(SpringProcessConnectionChangeListener listener) {
this.listeners.remove(listener);
}
private void announceConnectionClosed() {
for (SpringProcessConnectionChangeListener listener : this.listeners) {
listener.connectionClosed(processKey);
}
}
}

View File

@@ -23,11 +23,15 @@ public class SpringProcessDescriptor {
private final String processName;
private final VirtualMachineDescriptor vm;
private SpringProcessStatus status;
public SpringProcessDescriptor(String processKey, String processID, String processName, VirtualMachineDescriptor vm) {
this.processKey = processKey;
this.processID = processID;
this.processName = processName;
this.vm = vm;
this.status = SpringProcessStatus.UNKNOWN;
}
public String getProcessKey() {
@@ -47,17 +51,20 @@ public class SpringProcessDescriptor {
}
public String getLabel() {
return processID + " (" + processName + ") ";
return processID + " (" + processName + ")";
}
public void setStatus(SpringProcessStatus status) {
this.status = status;
}
public SpringProcessStatus getStatus() {
return this.status;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((processID == null) ? 0 : processID.hashCode());
result = prime * result + ((processKey == null) ? 0 : processKey.hashCode());
result = prime * result + ((processName == null) ? 0 : processName.hashCode());
return result;
return processKey.hashCode();
}
@Override
@@ -69,22 +76,15 @@ public class SpringProcessDescriptor {
if (getClass() != obj.getClass())
return false;
SpringProcessDescriptor other = (SpringProcessDescriptor) obj;
if (processID == null) {
if (other.processID != null)
return false;
} else if (!processID.equals(other.processID))
return false;
if (processKey == null) {
if (other.processKey != null)
return false;
} else if (!processKey.equals(other.processKey))
return false;
if (processName == null) {
if (other.processName != null)
return false;
} else if (!processName.equals(other.processName))
return false;
return true;
}
}

View File

@@ -0,0 +1,17 @@
/*******************************************************************************
* Copyright (c) 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
public enum SpringProcessStatus {
UNKNOWN, IGNORE, REGULAR, AUTO_CONNECT
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2019 Pivotal, Inc.
* Copyright (c) 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -74,13 +74,19 @@ public class SpringProcessTracker {
}
private void update() {
log.info("scan for local processes cycle...");
try {
this.localProcessConnector.searchForNewProcesses();
}
catch (Throwable e) {
log.error("error searching for local processes", e);
}
// log.info("scan for local processes cycle...");
// try {
// SpringProcessDescriptor[] autoConnectProcesses = this.localProcessConnector.getProcesses(true, SpringProcessStatus.AUTO_CONNECT);
//
// for (SpringProcessDescriptor process : autoConnectProcesses) {
// log.info("auto-connect to process: " + process.getProcessKey());
//
// this.localProcessConnector.connectProcess(process);
// }
// }
// catch (Throwable e) {
// log.error("error searching for local processes", e);
// }
}
}