keeping JMX connection open and react to connection lost event + integrating remote apps into the regular connect/disconnect command handling
This commit is contained in:
@@ -16,6 +16,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
@@ -94,8 +95,14 @@ public class LiveProcessCommandElement extends QuickAccessElement {
|
||||
|
||||
commandParams.setArguments(arguments);
|
||||
|
||||
CompletableFuture.allOf(usedLanguageServers.stream().map(ls ->
|
||||
ls.getWorkspaceService().executeCommand(commandParams)).toArray(CompletableFuture[]::new)).join();
|
||||
try {
|
||||
CompletableFuture.allOf(usedLanguageServers.stream().map(ls ->
|
||||
ls.getWorkspaceService().executeCommand(commandParams)).toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: better exception handling
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
@@ -59,9 +60,16 @@ public class LiveProcessCommandsQuickAccessProvider implements IQuickAccessCompu
|
||||
commandParams.setCommand(LiveProcessCommandElement.COMMAND_LIST_PROCESSES);
|
||||
|
||||
List<QuickAccessElement> res = Collections.synchronizedList(new ArrayList<>());
|
||||
CompletableFuture.allOf(usedLanguageServers.stream().map(ls ->
|
||||
ls.getWorkspaceService().executeCommand(commandParams).thenAcceptAsync(commandResult ->
|
||||
createCommandItems(res, commandResult))).toArray(CompletableFuture[]::new)).join();
|
||||
|
||||
try {
|
||||
CompletableFuture.allOf(usedLanguageServers.stream().map(ls ->
|
||||
ls.getWorkspaceService().executeCommand(commandParams).thenAcceptAsync(commandResult ->
|
||||
createCommandItems(res, commandResult))).toArray(CompletableFuture[]::new)).get(2000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: better error handling
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return res.toArray(new QuickAccessElement[res.size()]);
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
private final ProjectBasedPropertyIndexProvider adHocPropertyIndexProvider;
|
||||
|
||||
private final SpringProcessLiveDataProvider liveDataProvider;
|
||||
private final SpringProcessConnectorService liveDataConnector;
|
||||
private final SpringProcessConnectorService liveDataService;
|
||||
|
||||
private final SpringLiveChangeDetectionWatchdog liveChangeDetectionWatchdog;
|
||||
private final ProjectObserver projectObserver;
|
||||
@@ -153,47 +153,36 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
workspaceService.onWorkspaceSymbol(new BootJavaWorkspaceSymbolHandler(indexer,
|
||||
new LiveAppURLSymbolProvider(runningAppProvider)));
|
||||
|
||||
|
||||
//
|
||||
// live data component wiring
|
||||
//
|
||||
|
||||
// central live data components (to coordinate live data flow)
|
||||
liveDataProvider = new SpringProcessLiveDataProvider();
|
||||
liveDataService = new SpringProcessConnectorService(liveDataProvider);
|
||||
|
||||
// connect the live data provider with the hovers (for data extraction and live updates)
|
||||
hoverProvider = createHoverHandler(projectFinder, sourceLinks, liveDataProvider);
|
||||
new SpringProcessLiveHoverUpdater(server, hoverProvider, projectFinder, liveDataProvider);
|
||||
|
||||
liveDataConnector = new SpringProcessConnectorService();
|
||||
new SpringProcessConnectorRemote(server, liveDataConnector, liveDataProvider);
|
||||
// deal with locally running processes and their connections
|
||||
SpringProcessConnectorLocal liveDataLocalProcessConnector = new SpringProcessConnectorLocal(liveDataService, projectObserver);
|
||||
|
||||
// deal with configured remote connections
|
||||
SpringProcessConnectorRemote liveDataRemoteProcessConnector = new SpringProcessConnectorRemote(server, liveDataService);
|
||||
|
||||
// create and handle commands
|
||||
new SpringProcessCommandHandler(server, liveDataService, liveDataLocalProcessConnector, liveDataRemoteProcessConnector);
|
||||
|
||||
// track locally running processes and automatically connect to them if configured to do so
|
||||
liveProcessTracker = new SpringProcessTracker(liveDataLocalProcessConnector, serverParams.watchDogInterval);
|
||||
|
||||
SpringProcessConnectorLocal liveHoverLocalProcessConnector = new SpringProcessConnectorLocal(liveDataConnector, liveDataProvider, projectObserver);
|
||||
liveProcessTracker = new SpringProcessTracker(liveHoverLocalProcessConnector, serverParams.watchDogInterval);
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
new SpringProcessCommandHandler(server, liveDataConnector, liveHoverLocalProcessConnector);
|
||||
|
||||
// liveHoverWatchdog = new SpringLiveHoverWatchdog(server, hoverProvider, runningAppProvider,
|
||||
// projectFinder, projectObserver, serverParams.watchDogInterval);
|
||||
// documents.onDidChangeContent(params -> {
|
||||
// TextDocument doc = params.getDocument();
|
||||
// if (getInterestingLanguages().contains(doc.getLanguageId())) {
|
||||
// if (testHightlighter != null) {
|
||||
// getClient()
|
||||
// .highlight(new HighlightParams(params.getDocument().getId(), testHightlighter.apply(doc)));
|
||||
// } else {
|
||||
// try {
|
||||
// liveHoverWatchdog.watchDocument(doc.getUri());
|
||||
// liveHoverWatchdog.update(doc.getUri());
|
||||
// } catch (Throwable t) {
|
||||
// log.error("", t);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// documents.onDidClose(doc -> {
|
||||
// if (testHightlighter != null) {
|
||||
// getClient().highlight(new HighlightParams(doc.getId(), testHightlighter.apply(doc)));
|
||||
// } else {
|
||||
// liveHoverWatchdog.unwatchDocument(doc.getUri());
|
||||
// }
|
||||
// });
|
||||
|
||||
liveChangeDetectionWatchdog = new SpringLiveChangeDetectionWatchdog(
|
||||
this,
|
||||
server,
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.ExecuteCommandParams;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessConnectorRemote.RemoteBootAppData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -35,10 +36,13 @@ public class SpringProcessCommandHandler {
|
||||
|
||||
private final SpringProcessConnectorService connectorService;
|
||||
private final SpringProcessConnectorLocal localProcessConnector;
|
||||
private final SpringProcessConnectorRemote remoteProcessConnector;
|
||||
|
||||
public SpringProcessCommandHandler(SimpleLanguageServer server, SpringProcessConnectorService connectorService, SpringProcessConnectorLocal localProcessConnector) {
|
||||
public SpringProcessCommandHandler(SimpleLanguageServer server, SpringProcessConnectorService connectorService,
|
||||
SpringProcessConnectorLocal localProcessConnector, SpringProcessConnectorRemote remoteProcessConnector) {
|
||||
this.connectorService = connectorService;
|
||||
this.localProcessConnector = localProcessConnector;
|
||||
this.remoteProcessConnector = remoteProcessConnector;
|
||||
|
||||
server.onCommand(COMMAND_LIST_PROCESSES, (params) -> {
|
||||
return getProcessCommands();
|
||||
@@ -61,6 +65,8 @@ public class SpringProcessCommandHandler {
|
||||
private CompletableFuture<Object> connect(ExecuteCommandParams params) {
|
||||
String processKey = getProcessKey(params);
|
||||
if (processKey != null) {
|
||||
|
||||
// try local processes
|
||||
SpringProcessDescriptor[] processes = localProcessConnector.getProcesses(false, SpringProcessStatus.REGULAR);
|
||||
for (SpringProcessDescriptor process : processes) {
|
||||
if (process.getProcessKey().equals(processKey)) {
|
||||
@@ -68,6 +74,16 @@ public class SpringProcessCommandHandler {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
// try remote processes
|
||||
RemoteBootAppData[] remoteProcesses = remoteProcessConnector.getProcesses();
|
||||
for (RemoteBootAppData remoteProcess : remoteProcesses) {
|
||||
String key = SpringProcessConnectorRemote.getProcessKey(remoteProcess);
|
||||
if (processKey.equals(key)) {
|
||||
remoteProcessConnector.connectProcess(remoteProcess);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
@@ -108,13 +124,11 @@ public class SpringProcessCommandHandler {
|
||||
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);
|
||||
}
|
||||
LiveProcessCommand disconnectCommand = new LiveProcessCommand();
|
||||
disconnectCommand.setAction(COMMAND_DISCONNECT);
|
||||
disconnectCommand.setLabel(label);
|
||||
disconnectCommand.setProcessKey(processKey);
|
||||
result.add(disconnectCommand);
|
||||
|
||||
alreadyConnected.add(processKey);
|
||||
}
|
||||
@@ -136,6 +150,23 @@ public class SpringProcessCommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// other available remote processes
|
||||
RemoteBootAppData[] remoteProcesses = remoteProcessConnector.getProcesses();
|
||||
for (RemoteBootAppData remoteProcess : remoteProcesses) {
|
||||
String processKey = SpringProcessConnectorRemote.getProcessKey(remoteProcess);
|
||||
if (!alreadyConnected.contains(processKey)) {
|
||||
String label = "remote process: " + remoteProcess.getJmxurl();
|
||||
String action = COMMAND_CONNECT;
|
||||
|
||||
LiveProcessCommand command = new LiveProcessCommand();
|
||||
command.setAction(action);
|
||||
command.setLabel(label);
|
||||
command.setProcessKey(processKey);
|
||||
|
||||
result.add(command);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture((Object[]) result.toArray(new Object[result.size()]));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public interface SpringProcessConnector {
|
||||
String getLabel();
|
||||
|
||||
void connect() throws Exception;
|
||||
void refresh() throws Exception;
|
||||
SpringProcessLiveData refresh() throws Exception;
|
||||
void disconnect() throws Exception;
|
||||
|
||||
void addConnectorChangeListener(SpringProcessConnectionChangeListener listener);
|
||||
|
||||
@@ -67,14 +67,11 @@ public class SpringProcessConnectorLocal {
|
||||
private final Set<SpringProcessDescriptor> processes;
|
||||
|
||||
private final SpringProcessConnectorService processConnectorService;
|
||||
private final SpringProcessLiveDataProvider liveDataProvider;
|
||||
|
||||
public SpringProcessConnectorLocal(SpringProcessConnectorService processConnector, SpringProcessLiveDataProvider liveDataProvider,
|
||||
ProjectObserver projectObserver) {
|
||||
public SpringProcessConnectorLocal(SpringProcessConnectorService processConnector, ProjectObserver projectObserver) {
|
||||
this.projects = Collections.synchronizedCollection(new HashSet<>());
|
||||
this.processes = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
this.liveDataProvider = liveDataProvider;
|
||||
this.processConnectorService = processConnector;
|
||||
|
||||
projectObserver.addListener(new ProjectObserver.Listener() {
|
||||
@@ -253,7 +250,7 @@ public class SpringProcessConnectorLocal {
|
||||
String urlScheme = "http";
|
||||
|
||||
SpringProcessConnectorOverJMX connector = new SpringProcessConnectorOverJMX(
|
||||
liveDataProvider, descriptor.getProcessKey(), jmxAddress, urlScheme, processID, processName, null, null);
|
||||
descriptor.getProcessKey(), jmxAddress, urlScheme, processID, processName, null, null);
|
||||
|
||||
this.processConnectorService.connectProcess(descriptor.getProcessKey(), connector);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,14 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.remote.JMXConnectionNotification;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
@@ -27,22 +32,31 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringProcessConnectorOverJMX.class);
|
||||
|
||||
private final SpringProcessLiveDataProvider liveDataProvider;
|
||||
private static final String JMX_CLIENT_CONNECTION_CHECK_PERIOD_PROPERTY_KEY = "jmx.remote.x.client.connection.check.period";
|
||||
private static final long JMX_HEARTBEAT_INTERVAL = 1000;
|
||||
|
||||
private final String processKey;
|
||||
private final String jmxURL;
|
||||
private final String urlScheme;
|
||||
private final String processID;
|
||||
private final String processName;
|
||||
private final String host;
|
||||
private final String port;
|
||||
|
||||
// not final, might be updated with data from JMX process, if not initially set
|
||||
private String processID;
|
||||
private String processName;
|
||||
private String host;
|
||||
|
||||
private final List<SpringProcessConnectionChangeListener> listeners;
|
||||
|
||||
public SpringProcessConnectorOverJMX(SpringProcessLiveDataProvider liveDataProvider, String processKey, String jmxURL,
|
||||
private JMXConnector jmxConnection;
|
||||
private JMXServiceURL jmxServiceURL;
|
||||
|
||||
private final NotificationListener notificationListener;
|
||||
|
||||
public SpringProcessConnectorOverJMX(String processKey, String jmxURL,
|
||||
String urlScheme, String processID, String processName, String host, String port) {
|
||||
|
||||
this.liveDataProvider = liveDataProvider;
|
||||
this.processKey = processKey;
|
||||
|
||||
this.jmxURL = jmxURL;
|
||||
this.urlScheme = urlScheme;
|
||||
this.processID = processID;
|
||||
@@ -50,7 +64,28 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
||||
this.jmxConnection = null;
|
||||
this.jmxServiceURL = null;
|
||||
|
||||
this.listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
this.notificationListener = new NotificationListener() {
|
||||
@Override
|
||||
public void handleNotification(Notification notification, Object handback) {
|
||||
String notificationType = notification.getType();
|
||||
|
||||
if (JMXConnectionNotification.CLOSED.equals(notificationType)) {
|
||||
try {
|
||||
jmxConnection.removeConnectionNotificationListener(notificationListener);
|
||||
jmxConnection = null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("exception while reacting to connection close of: " + jmxURL, e);
|
||||
}
|
||||
announceConnectionClosed();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,40 +100,44 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
|
||||
@Override
|
||||
public void connect() throws Exception {
|
||||
jmxServiceURL = new JMXServiceURL(jmxURL);
|
||||
|
||||
Map<String, Object> environment = new HashMap<>();
|
||||
environment.put(JMX_CLIENT_CONNECTION_CHECK_PERIOD_PROPERTY_KEY, new Long(JMX_HEARTBEAT_INTERVAL));
|
||||
jmxConnection = JMXConnectorFactory.connect(jmxServiceURL, environment);
|
||||
|
||||
jmxConnection.addConnectionNotificationListener(notificationListener, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() throws Exception {
|
||||
public SpringProcessLiveData refresh() throws Exception {
|
||||
log.info("try to open JMX connection to: " + jmxURL);
|
||||
JMXConnector jmxConnector = null;
|
||||
try {
|
||||
SpringProcessLiveDataExtractorOverJMX springJMXConnector = new SpringProcessLiveDataExtractorOverJMX();
|
||||
|
||||
JMXServiceURL jmxServiceURL = new JMXServiceURL(jmxURL);
|
||||
jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
|
||||
|
||||
String hostName = host != null ? host : jmxServiceURL.getHost();
|
||||
|
||||
log.info("retrieve live data from: " + jmxURL);
|
||||
SpringProcessLiveData liveData = springJMXConnector.retrieveLiveData(jmxConnector, processID, processName, urlScheme, hostName, null, port);
|
||||
|
||||
if (liveData != null && liveData.getBeans() != null && !liveData.getBeans().isEmpty()) {
|
||||
this.liveDataProvider.add(processKey, liveData);
|
||||
return;
|
||||
|
||||
if (jmxConnection != null) {
|
||||
try {
|
||||
SpringProcessLiveDataExtractorOverJMX springJMXConnector = new SpringProcessLiveDataExtractorOverJMX();
|
||||
|
||||
if (this.host == null) {
|
||||
this.host = jmxServiceURL.getHost();
|
||||
}
|
||||
|
||||
log.info("retrieve live data from: " + jmxURL);
|
||||
SpringProcessLiveData liveData = springJMXConnector.retrieveLiveData(jmxConnection, processID, processName, urlScheme, host, null, port);
|
||||
|
||||
if (this.processID == null) {
|
||||
this.processID = liveData.getProcessID();
|
||||
}
|
||||
|
||||
if (this.processName == null) {
|
||||
this.processName = liveData.getProcessName();
|
||||
}
|
||||
|
||||
if (liveData != null && liveData.getBeans() != null && !liveData.getBeans().isEmpty()) {
|
||||
return liveData;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("exception while connecting to jmx: " + jmxURL, e);
|
||||
}
|
||||
finally {
|
||||
if (jmxConnector != null) {
|
||||
try {
|
||||
log.info("close JMX connection to: " + jmxURL);
|
||||
jmxConnector.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error closing the JMX connection for: " + jmxURL, e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("exception while connecting to jmx: " + jmxURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +146,18 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
|
||||
@Override
|
||||
public void disconnect() throws Exception {
|
||||
this.liveDataProvider.remove(processKey);
|
||||
try {
|
||||
if (jmxConnection != null) {
|
||||
|
||||
log.info("close JMX connection to: " + jmxURL);
|
||||
jmxConnection.removeConnectionNotificationListener(notificationListener);
|
||||
jmxConnection.close();
|
||||
jmxConnection = null;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error closing the JMX connection for: " + jmxURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,6 +176,4 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -141,12 +141,9 @@ public class SpringProcessConnectorRemote {
|
||||
*/
|
||||
private final Map<RemoteBootAppData, String> remoteAppInstances;
|
||||
private final SpringProcessConnectorService processConnectorService;
|
||||
private final SpringProcessLiveDataProvider liveDataProvider;
|
||||
|
||||
public SpringProcessConnectorRemote(SimpleLanguageServer server, SpringProcessConnectorService processConnector,
|
||||
SpringProcessLiveDataProvider liveDataProvider) {
|
||||
public SpringProcessConnectorRemote(SimpleLanguageServer server, SpringProcessConnectorService processConnector) {
|
||||
this.processConnectorService = processConnector;
|
||||
this.liveDataProvider = liveDataProvider;
|
||||
this.remoteAppInstances = new HashMap<>();
|
||||
|
||||
server.getWorkspaceService().onDidChangeConfiguraton(this::handleSettings);
|
||||
@@ -181,26 +178,34 @@ public class SpringProcessConnectorRemote {
|
||||
for (RemoteBootAppData data : newAppData) {
|
||||
remoteAppInstances.computeIfAbsent(data, (_appData) -> {
|
||||
logger.info("Creating RemoteStringBootApp: " + _appData);
|
||||
|
||||
String processKey = getProcessKey(_appData);
|
||||
String processID = null;
|
||||
String processName = null;
|
||||
String jmxURL = _appData.getJmxurl();
|
||||
String host = _appData.getHost();
|
||||
String port = _appData.getPort();
|
||||
String urlScheme = _appData.getUrlScheme();
|
||||
// boolean keepChecking = _appData.isKeepChecking();
|
||||
|
||||
SpringProcessConnectorOverJMX connector = new SpringProcessConnectorOverJMX(liveDataProvider, processKey, jmxURL, urlScheme, processID, processName, host, port);
|
||||
processConnectorService.connectProcess(processKey, connector);
|
||||
|
||||
connectProcess(_appData);
|
||||
return processKey;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static String getProcessKey(RemoteBootAppData appData) {
|
||||
return "remote";
|
||||
public static String getProcessKey(RemoteBootAppData appData) {
|
||||
return "remote process - " + appData.getJmxurl();
|
||||
}
|
||||
|
||||
public void connectProcess(RemoteBootAppData remoteProcess) {
|
||||
String processKey = getProcessKey(remoteProcess);
|
||||
String processID = null;
|
||||
String processName = null;
|
||||
String jmxURL = remoteProcess.getJmxurl();
|
||||
String host = remoteProcess.getHost();
|
||||
String port = remoteProcess.getPort();
|
||||
String urlScheme = remoteProcess.getUrlScheme();
|
||||
// boolean keepChecking = _appData.isKeepChecking();
|
||||
|
||||
SpringProcessConnectorOverJMX connector = new SpringProcessConnectorOverJMX(processKey, jmxURL, urlScheme, processID, processName, host, port);
|
||||
processConnectorService.connectProcess(processKey, connector);
|
||||
}
|
||||
|
||||
public RemoteBootAppData[] getProcesses() {
|
||||
Set<RemoteBootAppData> remoteApps = this.remoteAppInstances.keySet();
|
||||
return (RemoteBootAppData[]) remoteApps.toArray(new RemoteBootAppData[remoteApps.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,14 +28,26 @@ public class SpringProcessConnectorService {
|
||||
private static final int RETRY_MAX_NO = 10;
|
||||
private static final int RETRY_DELAY_IN_SECONDS = 3;
|
||||
|
||||
private final SpringProcessLiveDataProvider liveDataProvider;
|
||||
|
||||
private final ScheduledThreadPoolExecutor scheduler;
|
||||
private final ConcurrentMap<String, SpringProcessConnector> connectors;
|
||||
private final ConcurrentMap<String, Boolean> connectedSuccess;
|
||||
|
||||
private final SpringProcessConnectionChangeListener connectorListener;
|
||||
|
||||
public SpringProcessConnectorService() {
|
||||
public SpringProcessConnectorService(SpringProcessLiveDataProvider liveDataProvider) {
|
||||
this.liveDataProvider = liveDataProvider;
|
||||
this.scheduler = new ScheduledThreadPoolExecutor(10);
|
||||
this.connectors = new ConcurrentHashMap<>();
|
||||
this.connectedSuccess = new ConcurrentHashMap<>();
|
||||
|
||||
this.connectorListener = new SpringProcessConnectionChangeListener() {
|
||||
@Override
|
||||
public void connectionClosed(String processKey) {
|
||||
disconnectProcess(processKey);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void connectProcess(String processKey, SpringProcessConnector connector) {
|
||||
@@ -43,6 +55,8 @@ public class SpringProcessConnectorService {
|
||||
|
||||
this.connectors.put(processKey, connector);
|
||||
this.connectedSuccess.put(processKey, false);
|
||||
|
||||
connector.addConnectorChangeListener(connectorListener);
|
||||
|
||||
try {
|
||||
scheduleConnect(processKey, connector, 0, TimeUnit.SECONDS, 0);
|
||||
@@ -64,6 +78,8 @@ public class SpringProcessConnectorService {
|
||||
public void disconnectProcess(String processKey) {
|
||||
log.info("disconnect from process: " + processKey);
|
||||
|
||||
this.liveDataProvider.remove(processKey);
|
||||
|
||||
SpringProcessConnector connector = this.connectors.remove(processKey);
|
||||
this.connectedSuccess.put(processKey, false);
|
||||
|
||||
@@ -90,6 +106,7 @@ public class SpringProcessConnectorService {
|
||||
this.scheduler.schedule(() -> {
|
||||
try {
|
||||
connector.connect();
|
||||
refreshProcess(processKey);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info("problem occured during process connect", e);
|
||||
@@ -98,7 +115,6 @@ public class SpringProcessConnectorService {
|
||||
scheduleConnect(processKey, connector, RETRY_DELAY_IN_SECONDS, TimeUnit.SECONDS, retryNo + 1);
|
||||
}
|
||||
}
|
||||
refreshProcess(processKey);
|
||||
}, delay, unit);
|
||||
}
|
||||
|
||||
@@ -124,14 +140,20 @@ public class SpringProcessConnectorService {
|
||||
|
||||
this.scheduler.schedule(() -> {
|
||||
try {
|
||||
connector.refresh();
|
||||
this.connectedSuccess.put(processKey, true);
|
||||
SpringProcessLiveData newLiveData = connector.refresh();
|
||||
if (newLiveData != null) {
|
||||
if (!this.liveDataProvider.add(processKey, newLiveData)) {
|
||||
this.liveDataProvider.update(processKey, newLiveData);
|
||||
}
|
||||
|
||||
this.connectedSuccess.put(processKey, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info("problem occured during process live data refresh", e);
|
||||
|
||||
if (retryNo < RETRY_MAX_NO) {
|
||||
scheduleRefresh(processKey, connector, 3, TimeUnit.SECONDS, retryNo + 1);
|
||||
scheduleRefresh(processKey, connector, RETRY_DELAY_IN_SECONDS, TimeUnit.SECONDS, retryNo + 1);
|
||||
}
|
||||
else {
|
||||
disconnectProcess(processKey);
|
||||
|
||||
@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -68,7 +69,9 @@ public class SpringProcessLiveHoverUpdater {
|
||||
});
|
||||
|
||||
liveDataProvider.addLiveDataChangeListener(event -> {
|
||||
update();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
update();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user