createRunTarget(AzureTargetParams properties) {
+ return new AzureRunTarget(this, properties);
+ }
+
+ @Override
+ public ImageDescriptor getIcon() {
+ return BootDashAzurePlugin.getImageDescriptor("/icons/azure.png");
+ }
+
+ @Override
+ public ImageDescriptor getDisconnectedIcon() {
+ return BootDashAzurePlugin.getImageDescriptor("icons/azure-inactive.png");
+ }
+
+ @Override
+ public AzureTargetParams parseParams(String serializedTargetParams) {
+ Gson gson = new Gson();
+ return gson.fromJson(serializedTargetParams, AzureTargetParams.class);
+ }
+
+ @Override
+ public String serialize(AzureTargetParams targetParams) {
+ Gson gson = new Gson();
+ return gson.toJson(targetParams);
+ }
+
+ /**
+ * Connect to azure with credentials obtained by prompting the user
+ *
+ * @return When login is successful, a client in authenticated (but not targeted) state; otherwise null.
+ */
+ public STSAzureClient login(UserInteractions ui) {
+ try {
+ if (ui.confirmOperation("Obtaining Credentials via OAuth",
+ "To access your Azure Spring Cloud subscriptions, resources and services, " +
+ "STS needs to be authorized by you. A web browser will now be opened for that purpose.")
+ ) {
+ STSAzureClient client = new STSAzureClient();
+ client.authenticate();
+ return client;
+ }
+ } catch (Exception e) {
+ Log.log(e);
+ ui.errorPopup("Authentication failed", ExceptionUtil.getMessage(e));
+ }
+ return null;
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.azure/src/org/springframework/ide/eclipse/boot/dash/azure/runtarget/AzureTargetParams.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.azure/src/org/springframework/ide/eclipse/boot/dash/azure/runtarget/AzureTargetParams.java
new file mode 100644
index 000000000..3c41f1836
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.azure/src/org/springframework/ide/eclipse/boot/dash/azure/runtarget/AzureTargetParams.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.eclipse.boot.dash.azure.runtarget;
+
+import com.microsoft.azure.auth.AzureCredential;
+
+/**
+ * Json serialisation friendly object that contains all the data
+ * we need to establish connection to an Azure Spring Cloud cluster.
+ */
+public class AzureTargetParams {
+
+ private AzureCredential credentials;
+ private String subscriptionId;
+ private String subscriptionName;
+ private String clusterId;
+ private String clusterName;
+
+ public AzureTargetParams() {}
+
+ public AzureTargetParams(AzureCredential credentials, String subscriptionId, String subscriptionName, String clusterId, String clusterName) {
+ super();
+ this.credentials = credentials;
+ this.subscriptionId = subscriptionId;
+ this.subscriptionName = subscriptionName;
+ this.clusterId = clusterId;
+ this.clusterName = clusterName;
+ }
+
+ public AzureCredential getCredentials() {
+ return credentials;
+ }
+
+ public void setCredentials(AzureCredential credentials) {
+ this.credentials = credentials;
+ }
+
+ public String getSubscriptionId() {
+ return subscriptionId;
+ }
+
+ public void setSubscriptionId(String subscriptionId) {
+ this.subscriptionId = subscriptionId;
+ }
+
+ public String getClusterId() {
+ return clusterId;
+ }
+
+ public void setClusterId(String clusterId) {
+ this.clusterId = clusterId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getSubscriptionName() {
+ return this.subscriptionName;
+ }
+
+ public void setSubscriptionName(String subscriptionName) {
+ this.subscriptionName = subscriptionName;
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.classpath b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.classpath
new file mode 100644
index 000000000..50fea4658
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.project b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.project
new file mode 100644
index 000000000..ebd4c7802
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.project
@@ -0,0 +1,28 @@
+
+
+ org.springframework.ide.eclipse.boot.dash.cf
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.core.prefs b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..0c68a61dc
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.ui.prefs b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 000000000..c743e1c07
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,59 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.springframework.ide.eclipse.prefs b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.springframework.ide.eclipse.prefs
new file mode 100644
index 000000000..a12794d68
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/.settings/org.springframework.ide.eclipse.prefs
@@ -0,0 +1,2 @@
+boot.validation.initialized=true
+eclipse.preferences.version=1
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/META-INF/MANIFEST.MF b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/META-INF/MANIFEST.MF
new file mode 100755
index 000000000..d257af2a8
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/META-INF/MANIFEST.MF
@@ -0,0 +1,76 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.springframework.ide.eclipse.boot.dash.cf;singleton:=true
+Bundle-Version: 4.8.1.qualifier
+Bundle-Vendor: Pivotal Inc
+Bundle-Name: Spring Boot Dash CF Support
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.ui.ide,
+ org.springframework.ide.eclipse.boot.launch,
+ org.springframework.ide.eclipse.boot,
+ org.springframework.ide.eclipse.boot.dash,
+ org.springsource.ide.eclipse.commons.livexp,
+ com.google.guava;bundle-version="15.0.0",
+ org.springframework.ide.eclipse.boot.wizard,
+ io.projectreactor.reactor-core,
+ org.reactivestreams.reactive-streams,
+ org.eclipse.core.resources,
+ org.eclipse.debug.core,
+ org.eclipse.jdt.core,
+ org.springsource.ide.eclipse.commons.ui,
+ org.eclipse.ui.views.properties.tabbed,
+ org.eclipse.jdt.launching,
+ org.eclipse.debug.ui,
+ org.eclipse.jdt.debug.ui,
+ org.springsource.ide.eclipse.commons.core,
+ com.google.gson,
+ org.eclipse.ui.console,
+ javax.ws.rs;bundle-version="2.0.1",
+ org.springframework.ide.eclipse.beans.ui.live,
+ org.eclipse.compare,
+ org.eclipse.core.filebuffers,
+ org.eclipse.text,
+ org.springsource.ide.eclipse.commons.frameworks.core,
+ org.apache.httpcomponents.httpclient,
+ org.apache.httpcomponents.httpcore,
+ org.yaml.snakeyaml,
+ org.apache.commons.lang3,
+ org.springframework.ide.eclipse.editor.support,
+ org.eclipse.jface.text,
+ org.springsource.ide.eclipse.commons.cloudfoundry.client.v2,
+ org.eclipse.core.net,
+ org.eclipse.equinox.security,
+ org.eclipse.jdt.ui,
+ org.eclipse.ui.genericeditor,
+ org.eclipse.ui.editors,
+ com.hierynomus.sshj;bundle-version="0.24.0",
+ com.jcraft.jzlib;bundle-version="1.1.3",
+ org.bouncycastle.bcpkix;bundle-version="1.59.0",
+ org.bouncycastle.bcprov;bundle-version="1.59.0",
+ org.springsource.ide.eclipse.commons.boot.ls,
+ org.springframework.tooling.cloudfoundry.manifest.ls,
+ org.springframework.tooling.ls.eclipse.commons
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-Activator: org.springframework.ide.eclipse.boot.dash.cf.BootDashCfPlugin
+Bundle-ActivationPolicy: lazy
+Export-Package: org.springframework.ide.eclipse.boot.dash.cf,
+ org.springframework.ide.eclipse.boot.dash.cf.actions,
+ org.springframework.ide.eclipse.boot.dash.cf.client,
+ org.springframework.ide.eclipse.boot.dash.cf.client.v2,
+ org.springframework.ide.eclipse.boot.dash.cf.debug,
+ org.springframework.ide.eclipse.boot.dash.cf.deployment,
+ org.springframework.ide.eclipse.boot.dash.cf.dialogs,
+ org.springframework.ide.eclipse.boot.dash.cf.jmxtunnel,
+ org.springframework.ide.eclipse.boot.dash.cf.model,
+ org.springframework.ide.eclipse.boot.dash.cf.packaging,
+ org.springframework.ide.eclipse.boot.dash.cf.routes,
+ org.springframework.ide.eclipse.boot.dash.cf.runtarget,
+ org.springframework.ide.eclipse.boot.dash.cf.ui
+Bundle-ClassPath: .,
+ lib/spring-boot-loader-tools-1.2.3.RELEASE.jar
+Automatic-Module-Name: org.springframework.ide.eclipse.boot.dash.cf
+Import-Package: org.eclipse.core.runtime,
+ org.eclipse.core.runtime.jobs,
+ org.eclipse.core.runtime.preferences,
+ org.eclipse.osgi.util,
+ org.osgi.framework
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/build.properties b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/build.properties
new file mode 100755
index 000000000..b59f529db
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ icons/,\
+ lib/spring-boot-loader-tools-1.2.3.RELEASE.jar
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/icons/cloud_obj.png b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/icons/cloud_obj.png
new file mode 100644
index 000000000..7633c35fb
Binary files /dev/null and b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/icons/cloud_obj.png differ
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE-sources.jar b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE-sources.jar
new file mode 100644
index 000000000..cbb02c57f
Binary files /dev/null and b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE-sources.jar differ
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE.jar b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE.jar
new file mode 100644
index 000000000..d1a02b37c
Binary files /dev/null and b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/lib/spring-boot-loader-tools-1.2.3.RELEASE.jar differ
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/plugin.xml b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/plugin.xml
new file mode 100755
index 000000000..8feaf9cc8
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/plugin.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/pom.xml b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/pom.xml
new file mode 100755
index 000000000..786ef8f52
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot.ide
+ org.springframework.boot.ide
+ 4.8.1-SNAPSHOT
+ ../../eclipse-distribution/pom.xml
+
+
+ org.springframework.ide.eclipse
+ org.springframework.ide.eclipse.boot.dash.cf
+ eclipse-plugin
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-source-plugin
+ ${tycho-version}
+
+
+ plugin-source
+ generate-sources
+
+ plugin-source
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-p2-plugin
+ ${tycho-version}
+
+
+ second-generate-p2-metadata
+
+ p2-metadata
+
+ verify
+
+
+
+
+
+
+
+
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashCfPlugin.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashCfPlugin.java
new file mode 100644
index 000000000..434e762b3
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashCfPlugin.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2020 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:
+ * Phil Webb - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf;
+
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+public class BootDashCfPlugin extends AbstractUIPlugin {
+
+ private static final String PLUGIN_ID = "org.springframework.ide.eclipse.boot.dash.cf";
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ CompletableFuture.runAsync(() -> BootDashTargetInfoSynchronizer.start());
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ BootDashTargetInfoSynchronizer.stop();
+ super.stop(context);
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashInjections.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashInjections.java
new file mode 100644
index 000000000..a19f412fa
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashInjections.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.eclipse.boot.dash.cf;
+
+import org.springframework.ide.eclipse.boot.dash.api.RunTargetType;
+import org.springframework.ide.eclipse.boot.dash.cf.actions.CfBootDashActions;
+import org.springframework.ide.eclipse.boot.dash.cf.client.CloudFoundryClientFactory;
+import org.springframework.ide.eclipse.boot.dash.cf.client.v2.DefaultCloudFoundryClientFactoryV2;
+import org.springframework.ide.eclipse.boot.dash.cf.debug.DebugSupport;
+import org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugSupport;
+import org.springframework.ide.eclipse.boot.dash.cf.debug.SshTunnelFactory;
+import org.springframework.ide.eclipse.boot.dash.cf.debug.SshTunnelImpl;
+import org.springframework.ide.eclipse.boot.dash.cf.jmxtunnel.CloudFoundryRemoteBootAppsDataContributor;
+import org.springframework.ide.eclipse.boot.dash.cf.jmxtunnel.JmxSshTunnelManager;
+import org.springframework.ide.eclipse.boot.dash.cf.labels.BootDashCfLabels;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTargetType;
+import org.springframework.ide.eclipse.boot.dash.cf.ui.CfUserInteractions;
+import org.springframework.ide.eclipse.boot.dash.cf.ui.DefaultCfUserInteractions;
+import org.springframework.ide.eclipse.boot.dash.di.EclipseBeanLoader.Contribution;
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.labels.BootDashLabels;
+import org.springframework.ide.eclipse.boot.dash.model.DefaultBootDashModelContext;
+import org.springframework.ide.eclipse.boot.dash.views.BootDashActions;
+import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder;
+
+/**
+ * Contributes bean definitions to {@link DefaultBootDashModelContext}
+ */
+public class BootDashInjections implements Contribution {
+
+ @Override
+ public void applyBeanDefinitions(SimpleDIContext context) throws Exception {
+ //TargetType
+ context.def(RunTargetType.class, CloudFoundryRunTargetType::new);
+
+ //Auto sync of cf deployed apps with JMX over SSH tunnel with boot ls (for live hover/data features).
+ context.def(RemoteBootAppsDataHolder.Contributor.class, CloudFoundryRemoteBootAppsDataContributor::new);
+
+ //UI actions
+ context.defInstance(BootDashActions.Factory.class, CfBootDashActions.factory);
+
+ //BootDashLabels
+ context.defInstance(BootDashLabels.Contribution.class, BootDashCfLabels.jmxDecoration);
+
+ //cf internal
+ context.def(CfUserInteractions.class, DefaultCfUserInteractions::new);
+ context.defInstance(DebugSupport.class, SshDebugSupport.INSTANCE);
+ context.defInstance(SshTunnelFactory.class, SshTunnelImpl::new);
+ context.defInstance(JmxSshTunnelManager.class, new JmxSshTunnelManager());
+ context.defInstance(CloudFoundryClientFactory.class, DefaultCloudFoundryClientFactoryV2.INSTANCE);
+ }
+
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashTargetInfoSynchronizer.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashTargetInfoSynchronizer.java
new file mode 100644
index 000000000..d4a5fdb28
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/BootDashTargetInfoSynchronizer.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.eclipse.boot.dash.cf;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.client.ClientRequests;
+import org.springframework.ide.eclipse.boot.dash.cf.client.v2.DefaultClientRequestsV2;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CfTargetsInfo;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CfTargetsInfo.Target;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CfTargetsInfo.TargetDiagnosticMessages;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryTargetProperties;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
+import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
+import org.springframework.tooling.cloudfoundry.manifest.ls.CloudFoundryManifestLanguageServer;
+import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Helper methods to attach listener to the BootDash model and keep editor in sync with
+ * all connected cloudfoundry targets.
+ *
+ * Usage: just call the 'start()' method once, at the first time the information is desired.
+ */
+@SuppressWarnings("rawtypes")
+public class BootDashTargetInfoSynchronizer {
+
+ private static AtomicBoolean started = new AtomicBoolean(false);
+
+ public static void start() {
+ if (started.compareAndSet(false, true)) {
+ model().getRunTargets().addListener(targetsListener);
+ }
+ }
+
+ public static void stop() {
+ if (started.compareAndSet(true, false)) {
+ updateCloudTargetsInManifestEditor(ImmutableSet.of());
+ }
+ }
+
+ private static final ValueListener> targetsListener = (e, v) -> {
+ // On target changes, add the client listener in each target so that when the client changes, a notification is sent
+ addClientChangeListeners(e.getValue());
+ };
+
+ private static final ValueListener clientsChangedListener = (exp, client) -> {
+ if (client instanceof DefaultClientRequestsV2) {
+ addRefreshTokenListener((DefaultClientRequestsV2) client);
+ }
+ };
+
+ /**
+ * Add a listener to be notified when the refresh token becomes available OR
+ * changes
+ */
+ static private void addRefreshTokenListener(DefaultClientRequestsV2 client) {
+ if (client != null && client.getRefreshTokens() != null && model() != null
+ && model().getRunTargets() != null) {
+ client.getRefreshTokens().doOnNext((token) ->
+ // Although the refresh token change is for ONE client (i.e. one target)
+ // compute cloud target information for ALL currently connected targets
+ // as the manifest editor is updated with the full up-to-date list of connected
+ // boot dash targets
+ updateCloudTargetsInManifestEditor(model().getRunTargets().getValue())
+ ).subscribe();
+ client.getRefreshTokens().doOnComplete(() ->
+ updateCloudTargetsInManifestEditor(model().getRunTargets().getValue())
+ ).subscribe();
+ }
+ }
+
+ static private void updateCloudTargetsInManifestEditor(ImmutableSet value) {
+ Set toUpdate = value == null ? ImmutableSet.of() : value;
+
+ CfTargetsInfo targetsInfo = asTargetsInfo(toUpdate);
+ CloudFoundryManifestLanguageServer.setCfTargetLoginOptions(targetsInfo);
+ }
+
+ private static BootDashViewModel model() {
+ return BootDashActivator.getDefault().getModel();
+ }
+
+ private static void addClientChangeListeners(ImmutableSet targets) {
+ if (targets != null) {
+ for (RunTarget runTarget : targets) {
+ if (runTarget instanceof CloudFoundryRunTarget) {
+ ((CloudFoundryRunTarget) runTarget).getClientExp().addListener(clientsChangedListener);
+ }
+ }
+ }
+ }
+
+ private static CfTargetsInfo asTargetsInfo(Collection targets) {
+ List collectedTargets = new ArrayList<>();
+ for (RunTarget runTarget : targets) {
+ if (runTarget instanceof CloudFoundryRunTarget) {
+
+ CloudFoundryRunTarget cloudFoundryRunTarget = (CloudFoundryRunTarget) runTarget;
+ if (cloudFoundryRunTarget.isConnected()) {
+ String token = cloudFoundryRunTarget.getClient().getRefreshToken();
+ if (token != null) {
+ CloudFoundryTargetProperties properties = cloudFoundryRunTarget.getTargetProperties();
+ String target = properties.getUrl();
+ String org = properties.getOrganizationName();
+ String space = properties.getSpaceName();
+ boolean sslDisabled = properties.skipSslValidation();
+
+ CfTargetsInfo.Target integrationTarget = new Target();
+
+ integrationTarget.setApi(target);
+ integrationTarget.setOrg(org);
+ integrationTarget.setSpace(space);
+ integrationTarget.setSslDisabled(sslDisabled);
+ integrationTarget.setRefreshToken(token);
+ collectedTargets.add(integrationTarget);
+ }
+ }
+ }
+ }
+
+ CfTargetsInfo targetsInfo = new CfTargetsInfo();
+ targetsInfo.setCfTargets(collectedTargets);
+ targetsInfo.setDiagnosticMessages(getDiagnosticMessages());
+ return targetsInfo ;
+ }
+
+ // NOTE: using ':' to separate the "shorter" part of the message from the longer. The longer part may be shown in the UI by expanding the hover info
+ private static final String TARGET_SOURCE = "Boot Dashboard";
+ private static final String NO_ORG_SPACE = "Boot Dashboard - No org/space selected: Verify Cloud Foundry target connection in Boot Dashboard or login via 'cf' CLI";
+ // Make this a "generic" message, instead of using "Boot Dash" prefix as it shows general instructions when there are not targets
+ private static final String NO_TARGETS = "No Cloud Foundry targets found: Create a target in Boot Dashboard or login via 'cf' CLI";
+ private static final String CONNECTION_ERROR = "Boot Dashboard - Error connecting to Cloud Foundry target: Verify network connection or that existing target has valid credentials.";
+
+ private static TargetDiagnosticMessages getDiagnosticMessages() {
+ TargetDiagnosticMessages messages = new TargetDiagnosticMessages();
+ messages.setConnectionError(CONNECTION_ERROR);
+ messages.setNoOrgSpace(NO_ORG_SPACE);
+ messages.setNoTargetsFound(NO_TARGETS);
+ messages.setTargetSource(TARGET_SOURCE);
+ return messages;
+ }
+
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudAppDashElementsAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudAppDashElementsAction.java
new file mode 100644
index 000000000..02ba712a9
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudAppDashElementsAction.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.actions;
+
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction.Params;
+
+/**
+ * Action for {@link CloudAppDashElement} elements only
+ *
+ * @author Alex Boyko
+ *
+ */
+public class AbstractCloudAppDashElementsAction extends AbstractBootDashElementsAction {
+
+ public AbstractCloudAppDashElementsAction(Params params) {
+ super(params);
+ }
+
+ @Override
+ public void updateVisibility() {
+ boolean visible = false;
+ if (!getSelectedElements().isEmpty()) {
+ visible = true;
+ for (BootDashElement e : getSelectedElements()) {
+ if (!(e instanceof CloudAppDashElement)) {
+ visible = false;
+ break;
+ }
+ }
+ }
+ setVisible(visible);
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudDashModelAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudDashModelAction.java
new file mode 100644
index 000000000..245544ad6
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/AbstractCloudDashModelAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.actions;
+
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.cf.ui.CfUserInteractions;
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashModelAction;
+import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
+
+/**
+ * Action for Cloud Foundry dash model element
+ *
+ * @author Alex Boyko
+ *
+ */
+public class AbstractCloudDashModelAction extends AbstractBootDashModelAction {
+
+ protected AbstractCloudDashModelAction(LiveExpression section, SimpleDIContext ui) {
+ super(section, ui);
+ }
+
+ protected CfUserInteractions cfUi() {
+ return context.getBean(CfUserInteractions.class);
+ }
+
+ @Override
+ public void updateVisibility() {
+ this.setVisible(sectionSelection.getValue() instanceof CloudFoundryBootDashModel);
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CfBootDashActions.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CfBootDashActions.java
new file mode 100644
index 000000000..491850acb
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CfBootDashActions.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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.eclipse.boot.dash.cf.actions;
+
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveProcessCommandsExecutor;
+import org.springframework.ide.eclipse.boot.dash.livexp.MultiSelection;
+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.views.AbstractBootDashAction;
+import org.springframework.ide.eclipse.boot.dash.views.BootDashActions;
+import org.springframework.ide.eclipse.boot.dash.views.ToggleBootDashModelConnection;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction.Params;
+import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
+
+import com.google.common.collect.ImmutableList;
+
+public class CfBootDashActions {
+
+ public static BootDashActions.Factory factory = (
+ BootDashActions actions,
+ BootDashViewModel model,
+ MultiSelection selection,
+ LiveExpression section,
+ SimpleDIContext context,
+ LiveProcessCommandsExecutor liveProcessCmds
+ ) -> {
+
+ Params defaultActionParams = new Params(actions)
+ .setModel(model)
+ .setSelection(selection)
+ .setContext(context)
+ .setLiveProcessCmds(liveProcessCmds);
+
+ ImmutableList.Builder builder = ImmutableList.builder();
+ builder.add(new RestartApplicationOnlyAction(defaultActionParams));
+ builder.add(new SelectManifestAction(defaultActionParams));
+ builder.add(new CloudFoundryRestartWithRemoteDevClientAction(defaultActionParams));
+ builder.add(new EnableJmxSshTunnelAction(defaultActionParams));
+ builder.add(new ReconnectCloudConsoleAction(defaultActionParams));
+ if (section!=null) {
+ builder.add(new UpdatePasswordAction(section, context));
+ builder.add(new OpenCloudAdminConsoleAction(section, context));
+ builder.add(new CustmomizeTargetAppManagerURLAction(section, context));
+ }
+ return builder.build();
+ };
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CloudFoundryRestartWithRemoteDevClientAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CloudFoundryRestartWithRemoteDevClientAction.java
new file mode 100644
index 000000000..8954a87b8
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CloudFoundryRestartWithRemoteDevClientAction.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2017 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.actions;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener;
+
+/**
+ * Action for starting/restarting Remove DevTools Client application
+ *
+ * @author Alex Boyko
+ *
+ */
+public class CloudFoundryRestartWithRemoteDevClientAction extends AbstractCloudAppDashElementsAction {
+
+ private ElementStateListener stateListener;
+
+ public CloudFoundryRestartWithRemoteDevClientAction(Params params) {
+ super(params);
+ this.setText("(Re)start Remote DevTools Client");
+ this.setToolTipText("Restarts application with the Remote DevTools Client attched.");
+ URL url = FileLocator.find(Platform.getBundle("org.springframework.ide.eclipse.boot"), new Path("resources/icons/boot-devtools-icon.png"), null);
+ if (url != null) {
+ this.setImageDescriptor(ImageDescriptor.createFromURL(url));
+ }
+ if (model != null) {
+ model.addElementStateListener(stateListener = new ElementStateListener() {
+ public void stateChanged(BootDashElement e) {
+ if (getSelectedElements().contains(e) && !PlatformUI.getWorkbench().isClosing()) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ updateEnablement();
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ boolean enable = false;
+ if (!getSelectedElements().isEmpty()) {
+ enable = true;
+ for (BootDashElement e : getSelectedElements()) {
+ if (!(e instanceof CloudAppDashElement) || e.getProject() == null) {
+ enable = false;
+ }
+ }
+ }
+ this.setEnabled(enable);
+ }
+
+ @Override
+ public void run() {
+ for (BootDashElement _e : getSelectedElements()) {
+ if (_e instanceof CloudAppDashElement && _e.getBootDashModel() instanceof CloudFoundryBootDashModel && _e.getProject() != null) {
+ CloudAppDashElement e = (CloudAppDashElement) _e;
+ e.restartWithRemoteClient(ui(), e.createCancelationToken());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (model != null && stateListener != null) {
+ model.removeElementStateListener(stateListener);
+ stateListener = null;
+ }
+ super.dispose();
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CustmomizeTargetAppManagerURLAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CustmomizeTargetAppManagerURLAction.java
new file mode 100644
index 000000000..04e053d7c
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/CustmomizeTargetAppManagerURLAction.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.actions;
+
+import java.util.EnumSet;
+
+import org.springframework.ide.eclipse.boot.dash.cf.dialogs.CustomizeAppsManagerURLDialogModel;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
+import org.springsource.ide.eclipse.commons.core.pstore.PropertyStoreApi;
+import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
+
+public class CustmomizeTargetAppManagerURLAction extends AbstractCloudDashModelAction{
+
+ protected CustmomizeTargetAppManagerURLAction(LiveExpression section, SimpleDIContext context) {
+ super(section, context);
+ setText("Customize Cloud Admin Console URL...");
+ }
+
+ @Override
+ public void updateEnablement() {
+ this.setEnabled(isApplicable(sectionSelection.getValue()));
+ }
+
+ @Override
+ public void updateVisibility() {
+ this.setVisible(isApplicable(sectionSelection.getValue()));
+ }
+
+ private boolean isApplicable(BootDashModel section) {
+ if (section != null && section instanceof CloudFoundryBootDashModel) {
+ PropertyStoreApi props = section.getRunTarget().getType().getPersistentProperties();
+ return props != null;
+ }
+ return false;
+ }
+
+ @Override
+ public void run() {
+ final BootDashModel section = sectionSelection.getValue();
+ if (isApplicable(section)) {
+ CustomizeAppsManagerURLDialogModel model = new CustomizeAppsManagerURLDialogModel((CloudFoundryBootDashModel)section);
+ cfUi().openEditAppsManagerURLDialog(model);
+ }
+ }
+
+ @Override
+ public EnumSet showIn() {
+ return EnumSet.of(Location.CUSTOMIZE_MENU);
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/EnableJmxSshTunnelAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/EnableJmxSshTunnelAction.java
new file mode 100644
index 000000000..424506789
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/EnableJmxSshTunnelAction.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2018 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.eclipse.boot.dash.cf.actions;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener;
+import org.springframework.ide.eclipse.boot.dash.model.RunState;
+import org.springsource.ide.eclipse.commons.livexp.util.Log;
+
+public class EnableJmxSshTunnelAction extends AbstractCloudAppDashElementsAction {
+
+ private ElementStateListener stateListener;
+
+ public EnableJmxSshTunnelAction(Params params) {
+ super(params);
+ this.setText("Enable JMX Ssh Tunneling");
+ this.setToolTipText("Enables JMX on this app and creates an SSH Tunnel the next time the app is started.");
+ URL url = FileLocator.find(Platform.getBundle("org.springframework.ide.eclipse.boot.dash"), new Path("icons/link_to_editor.png"), null);
+ if (url != null) {
+ this.setImageDescriptor(ImageDescriptor.createFromURL(url));
+ }
+ if (model != null) {
+ model.addElementStateListener(stateListener = new ElementStateListener() {
+ @Override
+ public void stateChanged(BootDashElement e) {
+ if (getSelectedElements().contains(e) && !PlatformUI.getWorkbench().isClosing()) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ updateEnablement();
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ boolean enable = false;
+ boolean enableTunnel = false;
+ if (getSelectedElements().size()==1) {
+ BootDashElement e = getSelectedElements().iterator().next();
+ if (e instanceof CloudAppDashElement && e.getProject() != null) {
+ CloudAppDashElement cde = (CloudAppDashElement) e;
+ enable = true;
+ enableTunnel = !cde.getEnableJmxSshTunnel();
+ }
+ }
+ this.setEnabled(enable);
+ if (enable) {
+ setText((enableTunnel ? "Enable" : "Disable")+" JMX Ssh Tunnelling");
+ } else {
+ setText("Toggle JMX Ssh Tunnelling");
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (BootDashElement _e : getSelectedElements()) {
+ if (_e instanceof CloudAppDashElement && _e.getBootDashModel() instanceof CloudFoundryBootDashModel && _e.getProject() != null) {
+ CloudAppDashElement e = (CloudAppDashElement) _e;
+ boolean enable = !e.getEnableJmxSshTunnel();
+ e.setEnableJmxSshTunnel(enable);
+ RunState runstate = e.getRunState();
+ if (runstate!=RunState.INACTIVE) {
+ int answer = ui().confirmOperation((enable ? "Enabling" : "Disabling") +" JMX Requires Restart",
+ "Enabling JMX is done by setting environment parameters on startup. For this setting to take effect the app needs to be restarted.\n\n" +
+ "Do you want to restart now?",
+ new String[] {
+ "Yes, Restart NOW",
+ "No, I'll restart MANUALLY later"
+ },
+ 0
+ );
+ if (answer==0) {
+ RunState runningOrDebugging = runstate==RunState.DEBUGGING ? RunState.DEBUGGING : RunState.RUNNING;
+ e.restart(runningOrDebugging, ui());
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.log(e);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (model != null && stateListener != null) {
+ model.removeElementStateListener(stateListener);
+ stateListener = null;
+ }
+ super.dispose();
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/OpenCloudAdminConsoleAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/OpenCloudAdminConsoleAction.java
new file mode 100644
index 000000000..9eff60721
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/OpenCloudAdminConsoleAction.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.actions;
+
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
+import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
+import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
+
+/**
+ * @author Martin Lippert
+ */
+public class OpenCloudAdminConsoleAction extends AbstractCloudDashModelAction {
+
+ public OpenCloudAdminConsoleAction(LiveExpression sectionSelection, SimpleDIContext ui) {
+ super(sectionSelection, ui);
+ this.setText("Open Cloud Admin Console");
+ this.setToolTipText("Opens the Cloud Administration Console for this Cloud Foundry Space and Organisation");
+ this.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/cloud_obj.png"));
+ }
+
+ @Override
+ public void run() {
+ final BootDashModel targetModel = sectionSelection.getValue();
+ if (targetModel != null) {
+ RunTarget target = targetModel.getRunTarget();
+ if (target instanceof CloudFoundryRunTarget) {
+ ((CloudFoundryRunTarget) target).openCloudAdminConsole(ui());
+ }
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ final BootDashModel targetModel = sectionSelection.getValue();
+ if (targetModel != null) {
+ RunTarget runTarget = targetModel.getRunTarget();
+ this.setEnabled(runTarget instanceof CloudFoundryRunTarget);
+ } else {
+ this.setEnabled(false);
+ }
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/ReconnectCloudConsoleAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/ReconnectCloudConsoleAction.java
new file mode 100644
index 000000000..c84af7442
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/ReconnectCloudConsoleAction.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.eclipse.boot.dash.cf.actions;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+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.views.AbstractBootDashElementsAction;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction.Params;
+
+public class ReconnectCloudConsoleAction extends AbstractCloudAppDashElementsAction {
+
+ public ReconnectCloudConsoleAction(Params params) {
+ super(params);
+ this.setText("Reconnect Console");
+ this.setToolTipText("Reconnect Console");
+ this.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/open_console.png"));
+ this.setDisabledImageDescriptor(BootDashActivator.getImageDescriptor("icons/open_console_disabled.png"));
+ }
+
+ @Override
+ public void run() {
+ final Collection selecteds = getSelectedElements();
+
+ Job job = new Job("Reconnecting console") {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ doShowConsoles(selecteds);
+ return Status.OK_STATUS;
+ }
+
+ };
+ job.schedule();
+ }
+
+ protected void doShowConsoles(Collection selectedElements) {
+
+ if (selectedElements != null) {
+
+ Iterator it = selectedElements.iterator();
+
+ // Show first element only for now
+ if (it.hasNext()) {
+ BootDashElement element = selectedElements.iterator().next();
+ BootDashModel model = element.getBootDashModel();
+ try {
+ if (model.getElementConsoleManager() != null) {
+ model.getElementConsoleManager().reconnect(element);
+ }
+ } catch (Exception e) {
+ ui().errorPopup("Reconnect Console Failure", e.getMessage());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ boolean enable = false;
+ if (!getSelectedElements().isEmpty()) {
+ enable = true;
+ for (BootDashElement e : getSelectedElements()) {
+ if (!(e instanceof CloudAppDashElement)) {
+ enable = false;
+ break;
+ }
+ }
+ }
+
+ this.setEnabled(enable);
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/RestartApplicationOnlyAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/RestartApplicationOnlyAction.java
new file mode 100644
index 000000000..184fcca11
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/RestartApplicationOnlyAction.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2017 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.eclipse.boot.dash.cf.actions;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction;
+import org.springframework.ide.eclipse.boot.dash.views.AbstractBootDashElementsAction.Params;
+
+public class RestartApplicationOnlyAction extends AbstractCloudAppDashElementsAction {
+
+ public RestartApplicationOnlyAction(Params params) {
+ super(params);
+ this.setText("Restart Only");
+ this.setToolTipText("Restarts the application without uploading changes.");
+ this.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/restart.png"));
+ this.setDisabledImageDescriptor(BootDashActivator.getImageDescriptor("icons/restart_disabled.png"));
+ }
+
+ @Override
+ public void run() {
+ Job job = new Job("Restarting apps") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (BootDashElement el : getSelectedElements()) {
+
+ if (el instanceof CloudAppDashElement) {
+ try {
+ CloudAppDashElement cloudAppDashElement = (CloudAppDashElement) el;
+ cloudAppDashElement.restartOnlyAsynch(ui(), cloudAppDashElement.createCancelationToken());
+ } catch (Exception e) {
+ ui().errorPopup("Error restarting application", e.getMessage());
+ }
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ };
+ job.schedule();
+ }
+
+ @Override
+ public void updateEnablement() {
+ boolean enable = false;
+ if (!getSelectedElements().isEmpty()) {
+ enable = true;
+ for (BootDashElement e : getSelectedElements()) {
+ if (!(e instanceof CloudAppDashElement)) {
+ enable = false;
+ break;
+ }
+ }
+ }
+
+ this.setEnabled(enable);
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/SelectManifestAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/SelectManifestAction.java
new file mode 100644
index 000000000..fab71e1aa
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/SelectManifestAction.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.eclipse.boot.dash.cf.actions;
+
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.cf.ops.SelectManifestOp;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
+import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
+
+public class SelectManifestAction extends AbstractCloudAppDashElementsAction {
+
+ public SelectManifestAction(Params params) {
+ super(params);
+ params.getContext().assertDefinitionFor(UserInteractions.class);
+ this.setText("Select Manifest");
+ this.setToolTipText("Selects a manifest YAML file to use during application restart.");
+ this.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/selectmanifest.gif"));
+ }
+
+ @Override
+ public void run() {
+ CloudAppDashElement element = getSelectedCloudElementWithProject();
+ if (element != null) {
+ CloudFoundryBootDashModel model = element.getBootDashModel();
+ model.runAsynch(new SelectManifestOp(element), ui());
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ this.setEnabled(getSelectedCloudElementWithProject() != null);
+ }
+
+ protected CloudAppDashElement getSelectedCloudElementWithProject() {
+ if (getSelectedElements().size() == 1) {
+
+ for (BootDashElement e : getSelectedElements()) {
+ if (e instanceof CloudAppDashElement) {
+ CloudAppDashElement cde = (CloudAppDashElement) e;
+ if (cde.getProject() != null && cde.getProject().isAccessible()) {
+ return cde;
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/UpdatePasswordAction.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/UpdatePasswordAction.java
new file mode 100644
index 000000000..d7d215c9d
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/actions/UpdatePasswordAction.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.eclipse.boot.dash.cf.actions;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.core.runtime.Status;
+import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
+import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext;
+import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
+import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
+import org.springframework.ide.eclipse.boot.dash.model.RunTargetWithProperties;
+import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
+import org.springsource.ide.eclipse.commons.livexp.util.Log;
+
+public class UpdatePasswordAction extends AbstractCloudDashModelAction {
+
+ public UpdatePasswordAction(LiveExpression sectionSelection, SimpleDIContext context) {
+ super(sectionSelection, context);
+ this.setText("Update Password");
+ this.setToolTipText("Update password locally for the selected target.");
+ this.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/update_password.png"));
+ }
+
+ CompletableFuture lastRunCompletion = null;
+
+ /**
+ * This is meant for test-code only, so that test can we wait for the action (part f which is executed in
+ * a job) to complete.
+ */
+ public void waitFor() throws InterruptedException, ExecutionException {
+ if (lastRunCompletion!=null) {
+ lastRunCompletion.get();
+ }
+ }
+
+ @Override
+ public void run() {
+ CompletableFuture lastRunCompletion = this.lastRunCompletion = new CompletableFuture<>();
+ try {
+ final CloudFoundryBootDashModel targetModel = (CloudFoundryBootDashModel) sectionSelection.getValue();
+ final CloudFoundryRunTarget runTarget = targetModel.getRunTarget();
+ if (runTarget!=null) {
+ targetModel.refreshTracker.callAsync("Updating password...", () -> {
+ runTarget.updatePasswordAndConnect();
+ lastRunCompletion.complete(null);
+ return Status.OK_STATUS;
+ });
+ }
+ } catch (Exception e) {
+ Log.log(e);
+ }
+ }
+
+ @Override
+ public void updateEnablement() {
+ this.setEnabled(getCredentialsHolder(sectionSelection.getValue())!=null);
+ }
+
+ @Override
+ public void updateVisibility() {
+ setVisible(getCredentialsHolder(sectionSelection.getValue()) != null);
+ }
+
+ private RunTargetWithProperties getCredentialsHolder(BootDashModel section) {
+ if (section!=null) {
+ RunTarget target = section.getRunTarget();
+ if (target instanceof RunTargetWithProperties) {
+ RunTargetWithProperties targetWithProps = (RunTargetWithProperties) target;
+ if (targetWithProps.requiresCredentials()) {
+ return targetWithProps;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFAppState.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFAppState.java
new file mode 100644
index 000000000..5b8ead367
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFAppState.java
@@ -0,0 +1,9 @@
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+public enum CFAppState {
+
+ STOPPED,
+ STARTED,
+ UNKNOWN
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplication.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplication.java
new file mode 100644
index 000000000..341ea5819
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplication.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public interface CFApplication extends CFEntity {
+ //TODO: lots of this infos should be moved to application details
+
+ int getInstances();
+ int getRunningInstances();
+ int getMemory();
+ UUID getGuid();
+ List getServices();
+ String getBuildpackUrl();
+ List getUris();
+ CFAppState getState();
+ int getDiskQuota();
+ Integer getTimeout();
+ String getCommand();
+ String getStack();
+
+ Map getEnvAsMap();
+ String getHealthCheckType();
+ String getHealthCheckHttpEndpoint();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationArchive.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationArchive.java
new file mode 100644
index 000000000..e91ecf189
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationArchive.java
@@ -0,0 +1,5 @@
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+public interface CFApplicationArchive {
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationDetail.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationDetail.java
new file mode 100644
index 000000000..591dfb285
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFApplicationDetail.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import java.util.List;
+
+public interface CFApplicationDetail extends CFApplication {
+ List getInstanceDetails();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFBuildpack.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFBuildpack.java
new file mode 100644
index 000000000..40f2704ef
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFBuildpack.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+public interface CFBuildpack {
+ String getName();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFClientParams.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFClientParams.java
new file mode 100644
index 000000000..3632d0bef
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFClientParams.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import java.net.URI;
+
+import org.eclipse.core.runtime.Assert;
+import org.springframework.ide.eclipse.boot.core.BootActivator;
+import org.springframework.ide.eclipse.boot.dash.cf.client.CFCredentials.CFCredentialType;
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryTargetProperties;
+
+/**
+ * All the parameters needed to create a CF client.
+ *
+ * @author Kris De Volder
+ */
+public class CFClientParams {
+
+ private final String apiUrl;
+ private final String username;
+ private CFCredentials credentials;
+ private final boolean isSelfSigned;
+ private final boolean skipSslValidation;
+
+ private String orgName; // optional
+ private String spaceName; //optional
+
+ public CFClientParams(String apiUrl,
+ String username,
+ CFCredentials credentials,
+ boolean isSelfSigned,
+ String orgName,
+ String spaceName,
+ boolean skipSslValidation
+ ) {
+ Assert.isNotNull(apiUrl, "apiUrl is required");
+ Assert.isNotNull(credentials, "credentials required");
+ if (credentials.getType()==CFCredentialType.PASSWORD) {
+ Assert.isNotNull(username, "username is required");
+ }
+ this.apiUrl = apiUrl;
+ this.username = username;
+ this.credentials = credentials;
+ this.isSelfSigned = isSelfSigned;
+ this.skipSslValidation = skipSslValidation;
+ this.orgName = orgName;
+ this.spaceName = spaceName;
+ }
+
+ public CFClientParams(CloudFoundryTargetProperties targetProperties) throws Exception {
+ this(
+ targetProperties.getUrl(),
+ targetProperties.getUsername(),
+ targetProperties.getCredentials(),
+ targetProperties.isSelfsigned(),
+ targetProperties.getOrganizationName(),
+ targetProperties.getSpaceName(),
+ targetProperties.skipSslValidation()
+ );
+ }
+
+ public CFCredentials getCredentials() {
+ return credentials;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public boolean isSelfsigned() {
+ return isSelfSigned;
+ }
+
+ public boolean skipSslValidation() {
+ return skipSslValidation;
+ }
+
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ public String getOrgName() {
+ return orgName;
+ }
+
+ public void setOrgName(String orgName) {
+ this.orgName = orgName;
+ }
+
+ public String getSpaceName() {
+ return spaceName;
+ }
+
+ public void setSpaceName(String spaceName) {
+ this.spaceName = spaceName;
+ }
+
+ public String getHost() {
+ try {
+ URI uri = new URI(getApiUrl());
+ return uri.getHost();
+ } catch (Exception e) {
+ BootActivator.log(e);
+ }
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((apiUrl == null) ? 0 : apiUrl.hashCode());
+ result = prime * result + (isSelfSigned ? 1231 : 1237);
+ result = prime * result + ((orgName == null) ? 0 : orgName.hashCode());
+ result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
+ result = prime * result + ((spaceName == null) ? 0 : spaceName.hashCode());
+ result = prime * result + ((username == null) ? 0 : username.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CFClientParams other = (CFClientParams) obj;
+ if (apiUrl == null) {
+ if (other.apiUrl != null)
+ return false;
+ } else if (!apiUrl.equals(other.apiUrl))
+ return false;
+ if (isSelfSigned != other.isSelfSigned)
+ return false;
+ if (orgName == null) {
+ if (other.orgName != null)
+ return false;
+ } else if (!orgName.equals(other.orgName))
+ return false;
+ if (credentials == null) {
+ if (other.credentials != null)
+ return false;
+ } else if (!credentials.equals(other.credentials))
+ return false;
+ if (spaceName == null) {
+ if (other.spaceName != null)
+ return false;
+ } else if (!spaceName.equals(other.spaceName))
+ return false;
+ if (username == null) {
+ if (other.username != null)
+ return false;
+ } else if (!username.equals(other.username))
+ return false;
+ return true;
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCloudDomain.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCloudDomain.java
new file mode 100644
index 000000000..041f81e7b
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCloudDomain.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import org.springframework.ide.eclipse.boot.dash.cf.client.v2.CFDomainStatus;
+
+public interface CFCloudDomain {
+ String getName();
+ CFDomainType getType();
+ CFDomainStatus getStatus();
+
+ /**
+ * If the given hostAndDomain is of the form ${host}.${domain} then
+ * return the host part. Otherwise return null.
+ */
+ default String splitHost(String hostAndDomain) {
+ String name = getName();
+ if (hostAndDomain.endsWith("."+name)) {
+ return hostAndDomain.substring(0, hostAndDomain.length()-name.length()-1);
+ }
+ return null;
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCredentials.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCredentials.java
new file mode 100644
index 000000000..26548feee
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFCredentials.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.core.runtime.Assert;
+import org.springsource.ide.eclipse.commons.livexp.ui.Ilabelable;
+
+public class CFCredentials {
+
+ public enum CFCredentialType {
+ PASSWORD,
+ TEMPORARY_CODE,
+ REFRESH_TOKEN;
+
+ public LoginMethod toLoginMethod() {
+ switch (this) {
+ case PASSWORD:
+ return LoginMethod.PASSWORD;
+ case TEMPORARY_CODE:
+ return LoginMethod.TEMPORARY_CODE;
+ default:
+ return null;
+ }
+ }
+ }
+
+ public enum LoginMethod implements Ilabelable {
+ PASSWORD,
+ TEMPORARY_CODE;
+
+ @Override
+ public String getLabel() {
+ String[] pieces = name().split("_");
+ StringBuilder label = new StringBuilder();
+ for (int i = 0; i < pieces.length; i++) {
+ if (i>0) {
+ label.append(" ");
+ }
+ label.append(StringUtils.capitalize(pieces[i].toLowerCase()));
+ }
+ return label.toString();
+ }
+ }
+
+ private final CFCredentialType type;
+ private final String secret;
+
+ /**
+ * Deprecated, use fromLogin instead
+ */
+ @Deprecated
+ public static CFCredentials fromPassword(String password) {
+ return fromLogin(LoginMethod.PASSWORD, password);
+ }
+
+
+ public static CFCredentials fromLogin(LoginMethod method, String secret) {
+ CFCredentialType type;
+ switch (method) {
+ case PASSWORD:
+ type = CFCredentialType.PASSWORD;
+ break;
+ case TEMPORARY_CODE:
+ type = CFCredentialType.TEMPORARY_CODE;
+ break;
+ default:
+ throw new IllegalStateException("Bug! Missing switch case?");
+ }
+ return new CFCredentials(type, secret);
+ }
+
+ public static CFCredentials fromRefreshToken(String refreshToken) {
+ Assert.isNotNull(refreshToken);
+ return new CFCredentials(CFCredentialType.REFRESH_TOKEN, refreshToken);
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Private constuctor, use static `fromXXX` factory methods instead.
+ */
+ private CFCredentials(CFCredentialType type, String secret) {
+ this.type = type;
+ this.secret = secret;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((secret == null) ? 0 : secret.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CFCredentials other = (CFCredentials) obj;
+ if (secret == null) {
+ if (other.secret != null)
+ return false;
+ } else if (!secret.equals(other.secret))
+ return false;
+ if (type != other.type)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "CFCredentials [type=" + type + ", secret=" + hidePassword(type, secret) + "]";
+ }
+
+ private String hidePassword(CFCredentialType type, String password) {
+ if (password==null) {
+ return null;
+ }
+ return type==CFCredentialType.PASSWORD
+ ? "****"
+ : password;
+ }
+
+
+ public CFCredentialType getType() {
+ return type;
+ }
+
+ public static CFCredentials fromSsoToken(String ssoToken) {
+ return CFCredentials.fromLogin(LoginMethod.TEMPORARY_CODE, ssoToken);
+ }
+}
\ No newline at end of file
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFDomainType.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFDomainType.java
new file mode 100644
index 000000000..c3045c34a
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFDomainType.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Spring IDE Developers
+ * 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:
+ * Spring IDE Developers - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+public enum CFDomainType {
+ HTTP, TCP
+}
+
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFEntity.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFEntity.java
new file mode 100644
index 000000000..ff7618bff
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFEntity.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+public interface CFEntity {
+ String getName();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFExceptions.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFExceptions.java
new file mode 100644
index 000000000..1ababe0a5
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFExceptions.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import org.cloudfoundry.uaa.UaaException;
+import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
+
+/**
+ * Static methods to recognize specific types of exceptions CF client
+ * may throw.
+ *
+ * @author Kris De Volder
+ */
+public class CFExceptions {
+
+ public static boolean isAuthFailure(Exception e) {
+ String msg = ExceptionUtil.getMessage(e);
+ return msg.contains("Bad credentials") || ExceptionUtil.getDeepestCause(e) instanceof UaaException;
+ }
+
+ public static boolean isSSLCertificateFailure(Exception e) {
+ Throwable cause = ExceptionUtil.getDeepestCause(e);
+ return cause.getClass().getName().equals("sun.security.provider.certpath.SunCertPathBuilderException");
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceState.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceState.java
new file mode 100644
index 000000000..cc98f66b6
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceState.java
@@ -0,0 +1,5 @@
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+public enum CFInstanceState {
+ RUNNING, CRASHED, FLAPPING, STARTING, DOWN, UNKNOWN
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceStats.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceStats.java
new file mode 100644
index 000000000..6d0953f8f
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFInstanceStats.java
@@ -0,0 +1,7 @@
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+public interface CFInstanceStats {
+
+ CFInstanceState getState();
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFOrganization.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFOrganization.java
new file mode 100644
index 000000000..a6504fa02
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFOrganization.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import java.util.UUID;
+
+public interface CFOrganization extends CFEntity {
+ UUID getGuid();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFServiceInstance.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFServiceInstance.java
new file mode 100644
index 000000000..fa9f57d8f
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFServiceInstance.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+public interface CFServiceInstance extends CFEntity {
+
+ String getName();
+ String getService();
+ String getPlan();
+ String getDescription();
+ String getDocumentationUrl();
+ String getDashboardUrl();
+
+ //TODO: last operation info?
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFSpace.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFSpace.java
new file mode 100644
index 000000000..bb5e0b553
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFSpace.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+import java.util.UUID;
+
+public interface CFSpace extends CFEntity {
+ CFOrganization getOrganization();
+ UUID getGuid();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFStack.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFStack.java
new file mode 100644
index 000000000..29be393fa
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CFStack.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+public interface CFStack extends CFEntity {
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/ClientRequests.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/ClientRequests.java
new file mode 100644
index 000000000..6389e341c
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/ClientRequests.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.eclipse.boot.dash.cf.client;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.osgi.framework.Version;
+import org.springframework.ide.eclipse.boot.dash.cf.client.v2.CFPushArguments;
+import org.springframework.ide.eclipse.boot.dash.console.IApplicationLogConsole;
+import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
+import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public interface ClientRequests extends Disposable {
+
+ /**
+ * The actual Rest API version that cloud controller claims to be.
+ */
+ Version getApiVersion() throws Exception;
+
+ /**
+ * The minimum version that the CF V2 java client claims to support.
+ */
+ Version getSupportedApiVersion();
+
+ /**
+ * Returns null if the application does not exist. Throws some kind of Exception if there's any other kind of problem.
+ */
+ CFApplicationDetail getApplication(String appName) throws Exception;
+
+ //TODO: consider removing the getXXXSupport method and directly adding the apis that these support
+ // objects provide.
+ SshClientSupport getSshClientSupport() throws Exception;
+
+
+ void deleteApplication(String name) throws Exception;
+
+ List getApplicationsWithBasicInfo() throws Exception;
+ List getBuildpacks() throws Exception;
+ List getDomains() throws Exception;
+ List getServices() throws Exception;
+ List getSpaces() throws Exception;
+ List getStacks() throws Exception;
+ void restartApplication(String appName, CancelationToken token) throws Exception;
+ void stopApplication(String appName) throws Exception;
+ reactor.core.Disposable streamLogs(String appName, IApplicationLogConsole logConsole) throws Exception;
+ Flux getApplicationDetails(List appsToLookUp) throws Exception;
+ String getHealthCheck(UUID appGuid) throws Exception;
+ void setHealthCheck(UUID guid, String hcType) throws Exception;
+ boolean applicationExists(String appName) throws Exception;
+
+ //Added since v2:
+ void push(CFPushArguments args, CancelationToken cancelationToken) throws Exception;
+ Map getApplicationEnvironment(String appName) throws Exception;
+ Mono deleteServiceAsync(String serviceName);
+
+ /**
+ * Gets current value of the client's refresh token. Note that the token is only set once it is known.
+ * Initially, if a client is created via password auth, then the refreshToken won't be known until
+ * some operation has been executed.
+ *
+ * @return Refresh token if it is already known, null otherwise.
+ */
+ String getRefreshToken();
+ Mono getUserName();
+
+ /**
+ * The returned flux will provide the current token in its onNext immediately, if there is a current
+ * token already. Subsequent onNext will be fired whenever the token changes.
+ */
+ Flux getRefreshTokens();
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudAppInstances.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudAppInstances.java
new file mode 100644
index 000000000..354b7167b
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudAppInstances.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.eclipse.boot.dash.cf.client;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * A Cloud application with additional stats and instances information
+ *
+ * This should be removed. Use {@link CFApplicationDetail} instead. It contains
+ * all the same infos.
+ */
+@Deprecated
+public class CloudAppInstances {
+
+ private final CFApplication app;
+ private final List stats;
+
+ public CloudAppInstances(CFApplication app, List stats) {
+ Assert.isNotNull(app);
+ this.app = app;
+ this.stats = stats;
+ }
+
+ public CFApplication getApplication() {
+ return app;
+ }
+
+ public List getStats() {
+ return stats;
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudFoundryClientFactory.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudFoundryClientFactory.java
new file mode 100644
index 000000000..0df2c19fc
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/CloudFoundryClientFactory.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.eclipse.boot.dash.cf.client;
+
+import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryTargetProperties;
+
+public abstract class CloudFoundryClientFactory {
+
+ public abstract ClientRequests getClient(CFClientParams params);
+
+ /**
+ * Get the client for an existing {@link CloudFoundryRunTarget}. Note that
+ * this may require the password to be set for that runtarget.
+ *
+ * @param runTarget
+ * @return client if connection was successful.
+ * @throws Exception
+ * if there was an error connecting, including if password is
+ * not set or invalid.
+ */
+ public final ClientRequests getClient(CloudFoundryTargetProperties targetProperties) throws Exception {
+ return getClient(new CFClientParams(targetProperties));
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/HealthChecks.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/HealthChecks.java
new file mode 100644
index 000000000..b531e8b10
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/HealthChecks.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * 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.eclipse.boot.dash.cf.client;
+
+public class HealthChecks {
+
+ public static final String HC_PORT = "port";
+ public static final String HC_PROCESS = "process";
+ public static final String HC_HTTP = "http";
+ public static final String[] HC_ALL = {HC_PORT, HC_PROCESS, HC_HTTP};
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/InstanceState.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/InstanceState.java
new file mode 100644
index 000000000..de67ab7c3
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/InstanceState.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2009-2016 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.eclipse.boot.dash.cf.client;
+
+/**
+ * Enum used for the state of an instance
+ *
+ * Note: copied over from CF V1 client code.
+ *
+ * @author Thomas Risberg
+ */
+public enum InstanceState {
+ DOWN, STARTING, RUNNING, CRASHED, FLAPPING, UNKNOWN;
+
+ public static InstanceState valueOfWithDefault(String s) {
+ try {
+ return InstanceState.valueOf(s);
+ } catch (IllegalArgumentException e) {
+ return InstanceState.UNKNOWN;
+ }
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/RequestErrorHandler.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/RequestErrorHandler.java
new file mode 100644
index 000000000..63c1f2c99
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/RequestErrorHandler.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client;
+
+public class RequestErrorHandler {
+
+ /**
+ *
+ * @param e
+ * @return true if request error should be treated as an error and thrown. False error
+ * should be ignored.
+ */
+ public boolean throwError(Throwable e) {
+ return true;
+ }
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshClientSupport.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshClientSupport.java
new file mode 100644
index 000000000..35cbef140
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshClientSupport.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+import java.util.UUID;
+
+public interface SshClientSupport {
+
+ SshHost getSshHost() throws Exception;
+ String getSshUser(String appName, int instance) throws Exception;
+ String getSshCode() throws Exception;
+
+ /**
+ * Deprecated because it is not supported with V2. Use the method based on appName instead.
+ */
+ @Deprecated
+ String getSshUser(UUID appGuid, int instance) throws Exception;
+
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshHost.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshHost.java
new file mode 100644
index 000000000..f9fcf1975
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/SshHost.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 Pivotal Software, 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 Software, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.eclipse.boot.dash.cf.client;
+
+/**
+ * Info object containing various bits of info about the host to which an ssh
+ * client may wish to connect.
+ *
+ * @author Kris De Volder
+ */
+public class SshHost {
+
+ final private String host;
+
+ final private int port;
+
+ final private String fingerPrint;
+
+ public SshHost(String host, int port, String fingerPrint) {
+ super();
+ this.host = host;
+ this.port = port;
+ this.fingerPrint = fingerPrint;
+ }
+
+ public String getFingerPrint() {
+ return fingerPrint;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ @Override
+ public String toString() {
+ return "SshHost [host=" //$NON-NLS-1$
+ + host + ", port=" //$NON-NLS-1$
+ + port + ", fingerPrint=" //$NON-NLS-1$
+ + fingerPrint + "]";//$NON-NLS-1$
+ }
+}
diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/v2/ApplicationExtras.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/v2/ApplicationExtras.java
new file mode 100644
index 000000000..aaf953e1a
--- /dev/null
+++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf/src/org/springframework/ide/eclipse/boot/dash/cf/client/v2/ApplicationExtras.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.eclipse.boot.dash.cf.client.v2;
+
+import java.util.List;
+import java.util.Map;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * Extrat bits of info that are 'prefetched' asynchronously to fill
+ * out the CFApplication with info that C2 client doesn't initially return.
+ *
+ * @author Kris De Volder
+ */
+public interface ApplicationExtras {
+ Mono