Docker App in bootdash without actuator -> no automatic live hover

See: https://github.com/spring-projects/sts4/issues/716
This commit is contained in:
Kris De Volder
2022-07-26 15:50:16 -07:00
parent 35f4cc8292
commit 392d953bd9
32 changed files with 308 additions and 188 deletions

View File

@@ -53,8 +53,8 @@ import org.springframework.ide.eclipse.boot.dash.docker.exceptions.MissingBuildS
import org.springframework.ide.eclipse.boot.dash.docker.exceptions.MissingBuildTagException;
import org.springframework.ide.eclipse.boot.dash.docker.jmx.JmxSupport;
import org.springframework.ide.eclipse.boot.dash.docker.runtarget.BuildScriptLocator.BuildKind;
import org.springframework.ide.eclipse.boot.dash.docker.runtarget.DockerApp.BuildCommand;
import org.springframework.ide.eclipse.boot.dash.labels.BootDashLabels;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.RunState;
import org.springframework.ide.eclipse.boot.dash.model.remote.ChildBearing;
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
@@ -62,7 +62,6 @@ import org.springframework.ide.eclipse.boot.dash.util.LineBasedStreamGobler;
import org.springframework.ide.eclipse.boot.launch.util.PortFinder;
import org.springframework.ide.eclipse.boot.util.JavaProjectUtil;
import org.springsource.ide.eclipse.commons.core.pstore.PropertyStoreApi;
import org.springsource.ide.eclipse.commons.core.pstore.PropertyStores;
import org.springsource.ide.eclipse.commons.frameworks.core.util.JobUtil;
import org.springsource.ide.eclipse.commons.frameworks.core.util.StringUtils;
import org.springsource.ide.eclipse.commons.livexp.core.AbstractDisposable;
@@ -528,7 +527,10 @@ Successfully tagged fui:latest
builder.addAll(Arrays.asList(props.get(key, NO_STRINGS)));
builder.add(imageId);
props.put(key, builder.build().toArray(NO_STRINGS));
props.put(DockerImage.hasDevtoolsKey(imageId), context.projectHasDevtoolsDependency() && command.builtWithDevToolsArgs);
props.put(DockerImage.storageKey(imageId, ClasspathPropertyTester.HAS_DEVTOOLS),
context.projectHasClasspathProperty(ClasspathPropertyTester.HAS_DEVTOOLS) && command.builtWithDevToolsArgs);
props.put(DockerImage.storageKey(imageId, ClasspathPropertyTester.HAS_ACTUATORS),
context.projectHasClasspathProperty(ClasspathPropertyTester.HAS_ACTUATORS));
} catch (Exception e) {
Log.log(e);
}
@@ -637,7 +639,7 @@ Successfully tagged fui:latest
}
@Override
public boolean hasDevtoolsDependency() {
return context!=null && context.projectHasDevtoolsDependency();
}
public boolean hasClasspathProperty(ClasspathPropertyTester tester) {
return context!=null && context.projectHasClasspathProperty(tester);
}
}

View File

@@ -50,6 +50,7 @@ import org.springframework.ide.eclipse.boot.dash.console.LogType;
import org.springframework.ide.eclipse.boot.dash.devtools.DevtoolsUtil;
import org.springframework.ide.eclipse.boot.dash.docker.jmx.JmxSupport;
import org.springframework.ide.eclipse.boot.dash.docker.util.Ownable;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.RunState;
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
import org.springframework.ide.eclipse.boot.util.RetryUtil;
@@ -338,13 +339,12 @@ public class DockerContainer implements App, RunStateProvider, JmxConnectable, S
private static final boolean USE_DEDICATED_CLIENT = false;
@Override
public boolean hasDevtoolsDependency() {
public boolean hasClasspathProperty(ClasspathPropertyTester tester) {
if (context!=null) {
DockerImage image = context.getParent(DockerImage.class);
return image.hasDevtoolsDependency();
return image.hasClasspathProperty(tester);
}
return false;
}

View File

@@ -34,6 +34,7 @@ import org.springframework.ide.eclipse.boot.dash.api.ProjectRelatable;
import org.springframework.ide.eclipse.boot.dash.api.RunStateIconProvider;
import org.springframework.ide.eclipse.boot.dash.api.Styleable;
import org.springframework.ide.eclipse.boot.dash.api.TemporalBoolean;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.RunState;
import org.springframework.ide.eclipse.boot.dash.model.remote.ChildBearing;
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
@@ -246,9 +247,10 @@ public class DockerImage implements App, ChildBearing, Styleable, ProjectRelatab
}
@Override
public boolean hasDevtoolsDependency() {
public boolean hasClasspathProperty(ClasspathPropertyTester tester) {
PropertyStoreApi props = getTarget().getPersistentProperties();
return props.get(hasDevtoolsKey(image.getId()), false);
boolean result = props.get(storageKey(image.getId(), tester), false);
return result;
}
@Override
@@ -256,7 +258,7 @@ public class DockerImage implements App, ChildBearing, Styleable, ProjectRelatab
return TemporalBoolean.NEVER;
}
public static String hasDevtoolsKey(String imageId) {
return imageId +".hasDevtoolsDependency";
public static String storageKey(String imageId, ClasspathPropertyTester tester) {
return imageId + "." + tester.getId();
}
}

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -37,6 +38,7 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import org.apache.commons.io.IOUtils;
@@ -57,6 +59,7 @@ import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.springframework.ide.eclipse.beans.ui.live.model.LiveBeansModel;
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
import org.springframework.ide.eclipse.boot.dash.api.App;
import org.springframework.ide.eclipse.boot.dash.api.RunTargetType;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.RemoteBootDashModel;
@@ -75,6 +78,7 @@ import org.springframework.ide.eclipse.boot.dash.docker.ui.SelectDockerDaemonDia
import org.springframework.ide.eclipse.boot.dash.labels.BootDashLabels;
import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
import org.springframework.ide.eclipse.boot.dash.model.BootProjectDashElement;
import org.springframework.ide.eclipse.boot.dash.model.Failable;
import org.springframework.ide.eclipse.boot.dash.model.RefreshState;
@@ -99,8 +103,13 @@ import org.springframework.ide.eclipse.boot.dash.views.RunStateAction;
import org.springframework.ide.eclipse.boot.launch.devtools.BootDevtoolsClientLaunchConfigurationDelegate;
import org.springframework.ide.eclipse.boot.test.BootProjectTestHarness;
import org.springframework.ide.eclipse.boot.test.util.TestBracketter;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.Contributor;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.RemoteAppData;
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition;
import org.springsource.ide.eclipse.commons.livexp.core.LiveSets;
import org.springsource.ide.eclipse.commons.livexp.core.ObservableSet;
import org.springsource.ide.eclipse.commons.tests.util.StsTestCase;
import com.github.dockerjava.api.DockerClient;
@@ -218,6 +227,64 @@ public class BootDashDockerTests {
});
}
@Test
public void noAutoLiveHoverConnectWithoutActuator() throws Exception {
IProject project = projects.createBootWebProject("webby-no-actuators",
withJavaVersion("11")
);
GenericRemoteBootDashModel<DockerClient, DockerTargetParams> model = createDockerTarget();
dragAndDrop(project, model);
GenericRemoteAppElement dep = waitForDeployment(model, project);
GenericRemoteAppElement img = waitForChild(dep, d -> d instanceof DockerImage);
GenericRemoteAppElement con = waitForChild(img, d -> d instanceof DockerContainer);
List<RemoteBootAppsDataHolder.Contributor> remoteAppDataProviders = harness.context.injections.getBeans(RemoteBootAppsDataHolder.Contributor.class);
ObservableSet<RemoteAppData> remoteAppDataExp = RemoteBootAppsDataHolder.union(remoteAppDataProviders);
DockerContainer conData = (DockerContainer) con.getAppData();
String conName = conData.getName();
AtomicReference<RemoteAppData> found = new AtomicReference<>();
ACondition.waitFor("Remote app data", 2000, () -> {
for (RemoteAppData remoteApp : remoteAppDataExp.getValues()) {
String pid = remoteApp.getProcessId();
if (pid.equals(conName)) {
found.set(remoteApp);
}
}
assertThat("remoteApp data not found", found.get()!=null);
});
assertThat("manual connect should be enabled", found.get().isManualConnect());
}
@Test
public void autoLiveHoverConnectWithActuator() throws Exception {
IProject project = projects.createBootWebProject("webby-with-actuators",
withJavaVersion("11"),
withStarters("actuator")
);
GenericRemoteBootDashModel<DockerClient, DockerTargetParams> model = createDockerTarget();
dragAndDrop(project, model);
GenericRemoteAppElement dep = waitForDeployment(model, project);
GenericRemoteAppElement img = waitForChild(dep, d -> d instanceof DockerImage);
GenericRemoteAppElement con = waitForChild(img, d -> d instanceof DockerContainer);
List<RemoteBootAppsDataHolder.Contributor> remoteAppDataProviders = harness.context.injections.getBeans(RemoteBootAppsDataHolder.Contributor.class);
ObservableSet<RemoteAppData> remoteAppDataExp = RemoteBootAppsDataHolder.union(remoteAppDataProviders);
DockerContainer conData = (DockerContainer) con.getAppData();
String conName = conData.getName();
AtomicReference<RemoteAppData> found = new AtomicReference<>();
ACondition.waitFor("Remote app data", 2000, () -> {
for (RemoteAppData remoteApp : remoteAppDataExp.getValues()) {
String pid = remoteApp.getProcessId();
if (pid.equals(conName)) {
found.set(remoteApp);
}
}
assertThat("remoteApp data not found", found.get()!=null);
});
assertThat("manual connect should NOT be enabled", !found.get().isManualConnect());
}
@Test
public void devtoolsFullScenario() throws Exception {
GenericRemoteBootDashModel<DockerClient, DockerTargetParams> model = createDockerTarget();
@@ -499,10 +566,10 @@ public class BootDashDockerTests {
assertEquals(RunState.INACTIVE, con.getRunState());
});
assertConsoleContains(con, "[extShutdownHook]");
// assertConsoleContains(con, "[extShutdownHook]");
assertConsoleNotContains(con, "Starting WebbyApplication");
assertNoConsole(img);
assertConsoleContains(dep, "[extShutdownHook]");
// assertConsoleContains(dep, "[extShutdownHook]");
assertConsoleNotContains(dep, "Starting WebbyApplication");
RunStateAction startAction = restartAction();

View File

@@ -36,10 +36,12 @@ import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModelContext;
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
import org.springframework.ide.eclipse.boot.dash.model.SecuredCredentialsStore;
import org.springframework.ide.eclipse.boot.dash.model.remote.GenericRemoteAppElementDataContributor;
import org.springframework.ide.eclipse.boot.dash.test.mocks.MockScopedPropertyStore;
import org.springframework.ide.eclipse.boot.dash.test.mocks.MockSecuredCredentialStore;
import org.springframework.ide.eclipse.boot.dash.test.mocks.MockSshTunnel;
import org.springframework.ide.eclipse.boot.dash.views.BootDashActions;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.Contributor;
import org.springsource.ide.eclipse.commons.core.pstore.IPropertyStore;
import org.springsource.ide.eclipse.commons.core.pstore.IScopedPropertyStore;
import org.springsource.ide.eclipse.commons.core.pstore.InMemoryPropertyStore;
@@ -87,6 +89,7 @@ public class TestBootDashModelContext extends BootDashModelContext {
injections.defInstance(SshTunnelFactory.class, MockSshTunnel::new);
injections.defInstance(JmxSshTunnelManager.class, new JmxSshTunnelManager());
injections.def(CloudAppLogManager.class, CloudAppLogManager::new); //TODO: replace with a mock?
injections.def(GenericRemoteAppElementDataContributor.class, GenericRemoteAppElementDataContributor::new);
return injections;
}

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.api;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
/**
@@ -28,4 +29,5 @@ public interface AppContext {
RefreshStateTracker getRefreshTracker();
boolean projectHasDevtoolsDependency();
<T extends App> T getParent(Class<T> expectedType);
boolean projectHasClasspathProperty(ClasspathPropertyTester tester);
}

View File

@@ -0,0 +1,7 @@
package org.springframework.ide.eclipse.boot.dash.api;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
public interface ClasspathBearing extends App {
boolean hasClasspathProperty(ClasspathPropertyTester tester);
}

View File

@@ -1,10 +1,11 @@
package org.springframework.ide.eclipse.boot.dash.api;
public interface DevtoolsConnectable {
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
public interface DevtoolsConnectable extends ClasspathBearing {
String getDevtoolsSecret();
boolean hasDevtoolsDependency();
default TemporalBoolean isDevtoolsConnectable() {
return TemporalBoolean.now(hasDevtoolsDependency() && getDevtoolsSecret()!=null);
return TemporalBoolean.now(hasClasspathProperty(ClasspathPropertyTester.HAS_DEVTOOLS) && getDevtoolsSecret()!=null);
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.ide.eclipse.boot.dash.model.AbstractLaunchConfigurati
import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
import org.springframework.ide.eclipse.boot.dash.model.ButtonModel;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.RefreshState;
import org.springframework.ide.eclipse.boot.dash.model.RunState;
import org.springframework.ide.eclipse.boot.dash.model.TagUtils;
@@ -407,7 +408,7 @@ public class BootDashLabels implements Disposable {
styledLabel = new StyledString("- " + "Fetching runstate from JMX", stylers.italicColoured(muted));
}
} else if (column==DEVTOOLS) {
if (element.hasDevtoolsDependency()) {
if (element.hasClasspathProperty(ClasspathPropertyTester.HAS_DEVTOOLS)) {
Color grey = colorGrey();
Color green = colorGreen();
Color color = element.isDevtoolsGreenColor() ? green : grey;

View File

@@ -118,6 +118,8 @@ public interface BootDashElement extends App, Taggable {
Object getParent();
BootDashColumn[] getColumns();
boolean projectHasDevtoolsDependency();
boolean projectHasClasspathProperty(ClasspathPropertyTester tester);
String getUrl();
@@ -136,5 +138,5 @@ public interface BootDashElement extends App, Taggable {
default String getProtocol() { return "http"; }
default boolean isDevtoolsGreenColor() { return projectHasDevtoolsDependency(); }
default RefreshState getRefreshState() { return RefreshState.READY; }
default boolean hasDevtoolsDependency() { return projectHasDevtoolsDependency(); }
default boolean hasClasspathProperty(ClasspathPropertyTester tester) { return projectHasClasspathProperty(tester); }
}

View File

@@ -0,0 +1,39 @@
package org.springframework.ide.eclipse.boot.dash.model;
import org.eclipse.jdt.core.IClasspathEntry;
import org.springframework.ide.eclipse.boot.core.BootPropertyTester;
import com.google.common.base.Predicate;
public interface ClasspathPropertyTester {
String getId();
boolean test(IClasspathEntry[] classpath);
static final ClasspathPropertyTester HAS_DEVTOOLS = anyElement("HAS_DEVTOOLS", BootPropertyTester::isDevtoolsJar);
static final ClasspathPropertyTester HAS_ACTUATORS = anyElement("HAS_ACTUATORS", BootPropertyTester::isActuatorJar);
static ClasspathPropertyTester anyElement(String id, Predicate<IClasspathEntry> entryTester) {
return new ClasspathPropertyTester() {
@Override
public boolean test(IClasspathEntry[] classpath) {
for (IClasspathEntry e : classpath) {
if (entryTester.test(e)) {
return true;
}
}
return false;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return "ClasspathPropertyTester("+id+")";
}
};
}
}

View File

@@ -11,9 +11,13 @@
package org.springframework.ide.eclipse.boot.dash.model;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.springframework.ide.eclipse.beans.ui.live.model.TypeLookup;
@@ -32,6 +36,7 @@ import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.LiveSets;
import org.springsource.ide.eclipse.commons.livexp.core.ObservableSet;
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
import org.springsource.ide.eclipse.commons.livexp.util.Log;
import com.google.common.collect.ImmutableSet;
@@ -166,33 +171,58 @@ public abstract class WrappingBootDashElement<T> extends AbstractDisposable impl
}
}
private LiveExpression<Boolean> hasDevtools = null;
private Map<ClasspathPropertyTester, LiveExpression<Boolean>> classpathProperties = new HashMap<>();
@Override
public boolean projectHasClasspathProperty(ClasspathPropertyTester tester) {
LiveExpression<Boolean> exp;
synchronized (classpathProperties) {
exp = classpathProperties.computeIfAbsent(tester, t -> {
LiveExpression<Boolean> propertyExp = new LiveExpression<Boolean>(false) {
@Override
protected Boolean compute() {
IProject p = getProject();
try {
if (p!=null && p.isAccessible()) {
IJavaProject jp = JavaCore.create(p);
if (jp.exists()) {
IClasspathEntry[] classpath = jp.getResolvedClasspath(true);
if (classpath!=null) {
return tester.test(classpath);
}
}
}
} catch (Exception e) {
Log.log(e);
}
//Reaching here means we couldn't apply the tester, e.g. because classpath not (yet) available.
return false;
}
};
propertyExp.refresh();
ClasspathListenerManager classpathListener = new ClasspathListenerManager(new ClasspathListener() {
public void classpathChanged(IJavaProject jp) {
if (jp.getProject().equals(getProject())) {
propertyExp.refresh();
}
}
});
this.dependsOn(propertyExp);
this.addDisposableChild(classpathListener);
this.addDisposableChild(propertyExp);
return propertyExp;
});
}
return exp.getValue();
}
@Override
public final boolean projectHasDevtoolsDependency() {
if (hasDevtools==null) {
hasDevtools = new LiveExpression<Boolean>(false) {
@Override
protected Boolean compute() {
boolean val = BootPropertyTester.hasDevtools(getProject());
return val;
}
};
hasDevtools.refresh();
ClasspathListenerManager classpathListener = new ClasspathListenerManager(new ClasspathListener() {
public void classpathChanged(IJavaProject jp) {
if (jp.getProject().equals(getProject())) {
hasDevtools.refresh();
}
}
});
this.dependsOn(hasDevtools);
this.addDisposableChild(classpathListener);
this.addDisposableChild(hasDevtools);
}
return hasDevtools.getValue();
return projectHasClasspathProperty(ClasspathPropertyTester.HAS_DEVTOOLS);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void dependsOn(LiveExpression<?> liveProperty) {
liveProperty.addListener(new ValueListener() {

View File

@@ -15,7 +15,6 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Assert;
@@ -34,6 +33,7 @@ import org.springframework.ide.eclipse.boot.dash.api.ActualInstanceCount;
import org.springframework.ide.eclipse.boot.dash.api.App;
import org.springframework.ide.eclipse.boot.dash.api.AppConsole;
import org.springframework.ide.eclipse.boot.dash.api.AppContext;
import org.springframework.ide.eclipse.boot.dash.api.ClasspathBearing;
import org.springframework.ide.eclipse.boot.dash.api.DebuggableApp;
import org.springframework.ide.eclipse.boot.dash.api.Deletable;
import org.springframework.ide.eclipse.boot.dash.api.DesiredInstanceCount;
@@ -54,6 +54,7 @@ import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveDataCapableElem
import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveDataConnectionManagementActions.ExecuteCommandAction;
import org.springframework.ide.eclipse.boot.dash.livexp.DisposingFactory;
import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener;
import org.springframework.ide.eclipse.boot.dash.model.Failable;
import org.springframework.ide.eclipse.boot.dash.model.MissingLiveInfoMessages;
@@ -876,15 +877,6 @@ public class GenericRemoteAppElement extends WrappingBootDashElement<String> imp
return null;
}
@Override
public boolean hasDevtoolsDependency() {
App data = getAppData();
if (data instanceof DevtoolsConnectable) {
return ((DevtoolsConnectable) data).hasDevtoolsDependency();
}
return super.hasDevtoolsDependency();
}
@Override
public boolean isDevtoolsGreenColor() {
App data = getAppData();
@@ -907,6 +899,15 @@ public class GenericRemoteAppElement extends WrappingBootDashElement<String> imp
return selfMatch || childMatch(action);
}
@Override
public boolean hasClasspathProperty(ClasspathPropertyTester tester) {
App data = getAppData();
if (data instanceof ClasspathBearing) {
return ((ClasspathBearing) data).hasClasspathProperty(tester);
}
return projectHasClasspathProperty(tester);
}
private boolean childMatch(ExecuteCommandAction action) {
for (BootDashElement child : this.getChildren().getValues()) {
if (

View File

@@ -15,6 +15,7 @@ import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener;
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.Contributor;
import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.RemoteAppData;
import org.springsource.ide.eclipse.commons.livexp.core.AsyncLiveExpression.AsyncMode;
@@ -75,6 +76,7 @@ public class GenericRemoteAppElementDataContributor implements Contributor, Elem
data.setUrlScheme("http");
data.setPort(""+child.getLivePort());
data.setKeepChecking(false);
data.setManualConnect(!child.hasClasspathProperty(ClasspathPropertyTester.HAS_ACTUATORS));
data.setProcessId(child.getAppData().getName());
data.setProcessName(child.getConsoleDisplayName());
allApps.add(data);

View File

@@ -25,6 +25,7 @@ import org.eclipse.debug.core.Launch;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.JavaRuntime;
import org.springframework.ide.eclipse.boot.dash.model.ClasspathPropertyTester;
import org.springframework.ide.eclipse.boot.util.RetryUtil;
import org.springsource.ide.eclipse.commons.livexp.util.Log;
@@ -53,7 +54,7 @@ public class RemoteJavaLaunchUtil {
public synchronized static void synchronizeWith(GenericRemoteAppElement app) {
if (isDebuggable(app)) {
ILaunch l = ensureDebuggerAttached(app);
if (app.hasDevtoolsDependency()) {
if (app.hasClasspathProperty(ClasspathPropertyTester.HAS_DEVTOOLS)) {
l.setAttribute(DISABLE_HCR_LAUNCH_ATTRIBUTE, "true");
}
if (l!=null) {

View File

@@ -88,6 +88,15 @@ public class BootPropertyTester extends PropertyTester {
return false;
}
public static boolean isActuatorJar(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_LIBRARY) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.endsWith(".jar") && name.startsWith("spring-boot-actuator-");
}
return false;
}
public static boolean hasDevtools(IProject p) {
try {