Remove CF client and boot dash plugins and related tests
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
mvn clean package -Pe426 -Psnapshot -Dsigning.skip=true -Dhttpclient.retry-max=20 -Dmaven.test.skip=true -Declipse.p2.mirrors=false -Dtycho.localArtifacts=ignore -Dorg.eclipse.equinox.p2.transport.ecf.retry=5 -Dskip.osx.signing=true -Dskip.win.signing=true -Dskip.osx.notarizing=true
|
||||
mvn clean package -Pe427 -Psnapshot -Dsigning.skip=true -Dhttpclient.retry-max=20 -Dmaven.test.skip=true -Declipse.p2.mirrors=false -Dtycho.localArtifacts=ignore -Dorg.eclipse.equinox.p2.transport.ecf.retry=5 -Dskip.osx.signing=true -Dskip.win.signing=true -Dskip.osx.notarizing=true
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.springframework.boot.ide.product.e418</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -55,14 +55,12 @@
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.validation</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.wizard</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.dash.azure</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.dash.cf</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.dash.docker</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.boot.dash.feature</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.docker.client</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.maven.pom</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.xml.namespaces</module>
|
||||
<module>../eclipse-extensions/org.springframework.ide.eclipse.xml.namespaces.feature</module>
|
||||
<module>../eclipse-extensions/org.springsource.ide.eclipse.commons.cloudfoundry.client.v2</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src/"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/spring-boot-loader-tools-1.2.3.RELEASE.jar"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.springframework.ide.eclipse.boot.dash.cf</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,8 +0,0 @@
|
||||
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.release=disabled
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -1,59 +0,0 @@
|
||||
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
|
||||
@@ -1,2 +0,0 @@
|
||||
boot.validation.initialized=true
|
||||
eclipse.preferences.version=1
|
||||
@@ -1,79 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-SymbolicName: org.springframework.ide.eclipse.boot.dash.cf;singleton:=true
|
||||
Bundle-Version: 4.18.0.qualifier
|
||||
Bundle-Vendor: VMware, 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,
|
||||
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,
|
||||
com.google.gson,
|
||||
com.google.gson.annotations,
|
||||
com.google.gson.reflect,
|
||||
com.google.gson.stream
|
||||
@@ -1,7 +0,0 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
plugin.xml,\
|
||||
icons/,\
|
||||
lib/spring-boot-loader-tools-1.2.3.RELEASE.jar
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 697 B |
Binary file not shown.
Binary file not shown.
@@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.4"?>
|
||||
<plugin>
|
||||
<extension
|
||||
point="org.springframework.ide.eclipse.boot.dash.injections">
|
||||
<injection class="org.springframework.ide.eclipse.boot.dash.cf.BootDashInjections"/>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.compare.contentMergeViewers">
|
||||
<contentTypeBinding
|
||||
contentMergeViewerId="org.springframework.ide.eclipse.boot.dash.cf.yamlMergeViewer"
|
||||
contentTypeId="org.springframework.ide.eclipse.manifest.yml">
|
||||
</contentTypeBinding>
|
||||
<viewer
|
||||
class="org.springframework.ide.eclipse.boot.dash.cloudfoundry.deployment.YamlMergeViewerCreator"
|
||||
extensions="yml"
|
||||
id="org.springframework.ide.eclipse.boot.dash.cf.yamlMergeViewer"
|
||||
label="YAML Text Merge">
|
||||
</viewer>
|
||||
</extension>
|
||||
|
||||
<extension point="org.eclipse.debug.core.launchConfigurationTypes">
|
||||
<launchConfigurationType
|
||||
id="org.springframework.ide.eclipse.boot.dash.ssh.tunnel.launch"
|
||||
name="Boot Dash SSH Debug Tunnel"
|
||||
delegate="org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugLaunchConfigurationDelegate"
|
||||
modes="debug"
|
||||
sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
|
||||
sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
|
||||
</launchConfigurationType>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.views.properties.tabbed.propertySections">
|
||||
<propertySections
|
||||
contributorId="org.springframework.ide.eclipse.boot.dash.propertyContributor">
|
||||
<propertySection
|
||||
class="org.springframework.ide.eclipse.boot.dash.cf.views.properties.CloudFoundryAppPropertiesSection"
|
||||
id="org.springframework.ide.eclipse.boot.dash.section.CloudFoundryGeneral"
|
||||
tab="org.springframework.ide.eclipse.boot.dash.tab.General">
|
||||
<input
|
||||
type="org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement">
|
||||
</input>
|
||||
</propertySection>
|
||||
<propertySection
|
||||
class="org.springframework.ide.eclipse.boot.dash.cf.views.properties.CloudServiceGeneralPropertiesSection"
|
||||
id="org.springframework.ide.eclipse.boot.dash.section.CloudServiceSection"
|
||||
tab="org.springframework.ide.eclipse.boot.dash.tab.General">
|
||||
<input
|
||||
type="org.springframework.ide.eclipse.boot.dash.cf.model.CloudServiceInstanceDashElement">
|
||||
</input>
|
||||
</propertySection>
|
||||
</propertySections>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.debug.ui.launchConfigurationTypeImages">
|
||||
<launchConfigurationTypeImage
|
||||
icon="platform:/plugin/org.springframework.ide.eclipse.boot/resources/icons/boot-devtools-icon.png"
|
||||
configTypeID="org.springframework.ide.eclipse.boot.dash.ssh.tunnel.launch"
|
||||
id="org.springframework.ide.eclipse.boot.dash.ssh.tunnel.launch.image">
|
||||
</launchConfigurationTypeImage>
|
||||
</extension>
|
||||
|
||||
<extension point="org.eclipse.debug.ui.launchConfigurationTabGroups">
|
||||
<launchConfigurationTabGroup
|
||||
type="org.springframework.ide.eclipse.boot.dash.ssh.tunnel.launch"
|
||||
class="org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugLaunchConfigurationTabGroup"
|
||||
id="org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugLaunchConfigurationTabGroup">
|
||||
</launchConfigurationTabGroup>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.genericeditor.reconcilers">
|
||||
<reconciler
|
||||
class="org.springframework.ide.eclipse.boot.dash.cf.deployment.ApplicationNameReconciler"
|
||||
contentType="org.springframework.ide.eclipse.manifest.yml">
|
||||
<enabledWhen>
|
||||
<with
|
||||
variable="editor">
|
||||
<test
|
||||
property="org.springframework.ide.eclipse.boot.EmbeddedEditor.context"
|
||||
value="deployment-properties-dialog">
|
||||
</test>
|
||||
</with>
|
||||
</enabledWhen>
|
||||
</reconciler>
|
||||
</extension>
|
||||
</plugin>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot.ide</groupId>
|
||||
<artifactId>org.springframework.boot.ide</artifactId>
|
||||
<version>4.18.0-SNAPSHOT</version>
|
||||
<relativePath>../../eclipse-distribution/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.springframework.ide.eclipse</groupId>
|
||||
<artifactId>org.springframework.ide.eclipse.boot.dash.cf</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-p2-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>second-generate-p2-metadata</id>
|
||||
<goals>
|
||||
<goal>p2-metadata</goal>
|
||||
</goals>
|
||||
<phase>verify</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,34 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<ImmutableSet<RunTarget>> 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<ClientRequests> 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<RunTarget> value) {
|
||||
Set<RunTarget> 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<RunTarget> targets) {
|
||||
if (targets != null) {
|
||||
for (RunTarget runTarget : targets) {
|
||||
if (runTarget instanceof CloudFoundryRunTarget) {
|
||||
((CloudFoundryRunTarget) runTarget).getClientExp().addListener(clientsChangedListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CfTargetsInfo asTargetsInfo(Collection<RunTarget> targets) {
|
||||
List<CfTargetsInfo.Target> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashModel> section, SimpleDIContext ui) {
|
||||
super(section, ui);
|
||||
}
|
||||
|
||||
protected CfUserInteractions cfUi() {
|
||||
return context.getBean(CfUserInteractions.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVisibility() {
|
||||
this.setVisible(sectionSelection.getValue() instanceof CloudFoundryBootDashModel);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashElement> selection,
|
||||
LiveExpression<BootDashModel> section,
|
||||
SimpleDIContext context,
|
||||
LiveProcessCommandsExecutor liveProcessCmds
|
||||
) -> {
|
||||
|
||||
Params defaultActionParams = new Params(actions)
|
||||
.setModel(model)
|
||||
.setSelection(selection)
|
||||
.setContext(context)
|
||||
.setLiveProcessCmds(liveProcessCmds);
|
||||
|
||||
ImmutableList.Builder<AbstractBootDashAction> 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();
|
||||
};
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashModel> 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<Location> showIn() {
|
||||
return EnumSet.of(Location.CUSTOMIZE_MENU);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashModel> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashElement> 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<BootDashElement> selectedElements) {
|
||||
|
||||
if (selectedElements != null) {
|
||||
|
||||
Iterator<BootDashElement> 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);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<BootDashModel> 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<Void> 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<Void> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.client;
|
||||
|
||||
public enum CFAppState {
|
||||
|
||||
STOPPED,
|
||||
STARTED,
|
||||
UNKNOWN
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<String> getServices();
|
||||
String getBuildpackUrl();
|
||||
List<String> getUris();
|
||||
CFAppState getState();
|
||||
int getDiskQuota();
|
||||
Integer getTimeout();
|
||||
String getCommand();
|
||||
String getStack();
|
||||
|
||||
Map<String,String> getEnvAsMap();
|
||||
String getHealthCheckType();
|
||||
String getHealthCheckHttpEndpoint();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.client;
|
||||
|
||||
public interface CFApplicationArchive {
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<CFInstanceStats> getInstanceDetails();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.client;
|
||||
|
||||
public enum CFInstanceState {
|
||||
RUNNING, CRASHED, FLAPPING, STARTING, DOWN, UNKNOWN
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.client;
|
||||
|
||||
public interface CFInstanceStats {
|
||||
|
||||
CFInstanceState getState();
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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?
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 {
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<CFApplication> getApplicationsWithBasicInfo() throws Exception;
|
||||
List<CFBuildpack> getBuildpacks() throws Exception;
|
||||
List<CFCloudDomain> getDomains() throws Exception;
|
||||
List<CFServiceInstance> getServices() throws Exception;
|
||||
List<CFSpace> getSpaces() throws Exception;
|
||||
List<CFStack> 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<CFApplicationDetail> getApplicationDetails(List<CFApplication> 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<String, String> getApplicationEnvironment(String appName) throws Exception;
|
||||
Mono<Void> 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<String> 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<String> getRefreshTokens();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<CFInstanceStats> stats;
|
||||
|
||||
public CloudAppInstances(CFApplication app, List<CFInstanceStats> stats) {
|
||||
Assert.isNotNull(app);
|
||||
this.app = app;
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
public CFApplication getApplication() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public List<CFInstanceStats> getStats() {
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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};
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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$
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<Map<String,String>> getEnv();
|
||||
Mono<List<String>> getServices();
|
||||
Mono<String> getBuildpack();
|
||||
Mono<String> getStack();
|
||||
Mono<Integer> getTimeout();
|
||||
Mono<String> getCommand();
|
||||
Mono<String> getHealthCheckType();
|
||||
Mono<String> getHealthCheckHttpEndpoint();
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.springframework.ide.eclipse.boot.dash.cf.client.CFApplicationDetail;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFInstanceStats;
|
||||
|
||||
public class CFApplicationDetailData extends CFApplicationSummaryData implements CFApplicationDetail {
|
||||
|
||||
private List<CFInstanceStats> instanceDetails;
|
||||
|
||||
public CFApplicationDetailData(
|
||||
CFApplicationSummaryData app,
|
||||
List<CFInstanceStats> instanceDetails
|
||||
) {
|
||||
super(
|
||||
app.getName(),
|
||||
app.getInstances(),
|
||||
app.getRunningInstances(),
|
||||
app.getMemory(),
|
||||
app.getGuid(),
|
||||
app.getUris(),
|
||||
app.getState(),
|
||||
app.getDiskQuota(),
|
||||
app.extras
|
||||
);
|
||||
this.instanceDetails = instanceDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CFInstanceStats> getInstanceDetails() {
|
||||
return instanceDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("CFApplicationDetail(\n");
|
||||
buf.append(" name = "+getName()+"\n");
|
||||
buf.append(" instance = "+getInstances()+"\n");
|
||||
buf.append(" runningInstances = "+getRunningInstances()+"\n");
|
||||
buf.append(" memory = "+getMemory()+"\n");
|
||||
buf.append(" guid = "+getGuid()+"\n");
|
||||
buf.append(" uris = "+getUris()+"\n");
|
||||
buf.append(" state = "+getState()+"\n");
|
||||
buf.append(" diskQuota = "+getDiskQuota()+"\n");
|
||||
buf.append(" instanceDetails = "+getInstanceDetails()+"\n");
|
||||
buf.append(")\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.util.UUID;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFAppState;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFApplication;
|
||||
|
||||
public class CFApplicationSummaryData implements CFApplication {
|
||||
|
||||
private String name;
|
||||
private int instances;
|
||||
private int runningInstances;
|
||||
private int memory;
|
||||
private UUID guid;
|
||||
private List<String> uris;
|
||||
private CFAppState state;
|
||||
private int diskQuota;
|
||||
protected ApplicationExtras extras;
|
||||
|
||||
public CFApplicationSummaryData(
|
||||
String name,
|
||||
int instances,
|
||||
int runningInstances,
|
||||
int memory,
|
||||
UUID guid,
|
||||
List<String> uris,
|
||||
CFAppState state,
|
||||
int diskQuota,
|
||||
ApplicationExtras extras
|
||||
) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.instances = instances;
|
||||
this.runningInstances = runningInstances;
|
||||
this.memory = memory;
|
||||
this.guid = guid;
|
||||
this.uris = uris;
|
||||
this.state = state;
|
||||
this.diskQuota = diskQuota;
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstances() {
|
||||
return instances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRunningInstances() {
|
||||
return runningInstances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getGuid() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServices() {
|
||||
return extras.getServices().block(DefaultClientRequestsV2.GET_SERVICES_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBuildpackUrl() {
|
||||
return extras.getBuildpack().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUris() {
|
||||
return uris;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFAppState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDiskQuota() {
|
||||
return diskQuota;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return extras.getTimeout().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHealthCheckType() {
|
||||
return extras.getHealthCheckType().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommand() {
|
||||
return extras.getCommand().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStack() {
|
||||
return extras.getStack().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getEnvAsMap() {
|
||||
return extras.getEnv().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHealthCheckHttpEndpoint() {
|
||||
return extras.getHealthCheckHttpEndpoint().block(DefaultClientRequestsV2.GET_SMALL_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.v2;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCloudDomain;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFDomainType;
|
||||
|
||||
public final class CFCloudDomainData implements CFCloudDomain {
|
||||
private final String name;
|
||||
private final CFDomainType type;
|
||||
private final CFDomainStatus status;
|
||||
|
||||
public CFCloudDomainData(String name, CFDomainType type, CFDomainStatus status) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public CFCloudDomainData(String name) {
|
||||
this(name, CFDomainType.HTTP, CFDomainStatus.SHARED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFDomainType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFDomainStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CFCloudDomainData [name=" + name + ", type=" + type + ", status=" + status + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((status == null) ? 0 : status.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;
|
||||
CFCloudDomainData other = (CFCloudDomainData) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (status != other.status)
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.v2;
|
||||
|
||||
public enum CFDomainStatus {
|
||||
OWNED, SHARED
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.deployment.DeploymentProperties;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Arguments passed to push operation.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
* @author Nieraj Singh
|
||||
*/
|
||||
public class CFPushArguments implements AutoCloseable {
|
||||
private List<String> routes = ImmutableList.of();
|
||||
private String appName;
|
||||
private Integer memory;
|
||||
private Integer diskQuota;
|
||||
private Integer timeout;
|
||||
private String buildpack;
|
||||
private String command;
|
||||
private String stack;
|
||||
private String healthCheckType;
|
||||
private Map<String, String> env = ImmutableMap.of();
|
||||
private Integer instances;
|
||||
private List<String> services = ImmutableList.of();
|
||||
private File applicationDataAsFile;
|
||||
private boolean noStart = false;
|
||||
private boolean randomRoute = false;
|
||||
private String healthCheckHttpEndpoint;
|
||||
|
||||
public CFPushArguments() {
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
public Integer getMemory() {
|
||||
return memory;
|
||||
}
|
||||
public void setMemory(Integer memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
public Integer getDiskQuota() {
|
||||
return diskQuota;
|
||||
}
|
||||
public void setDiskQuota(Integer diskQuota) {
|
||||
this.diskQuota = diskQuota;
|
||||
}
|
||||
public Integer getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
public void setTimeout(Integer timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
public String getBuildpack() {
|
||||
return buildpack;
|
||||
}
|
||||
public void setBuildpack(String buildpack) {
|
||||
this.buildpack = buildpack;
|
||||
}
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
public String getStack() {
|
||||
return stack;
|
||||
}
|
||||
public void setStack(String stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
public Map<String, String> getEnv() {
|
||||
return env;
|
||||
}
|
||||
public void setEnv(Map<String, String> env) {
|
||||
this.env = env;
|
||||
}
|
||||
public Integer getInstances() {
|
||||
return instances;
|
||||
}
|
||||
public void setInstances(Integer instances) {
|
||||
this.instances = instances;
|
||||
}
|
||||
public List<String> getServices() {
|
||||
return services;
|
||||
}
|
||||
public void setServices(List<String> services) {
|
||||
this.services = services;
|
||||
}
|
||||
public boolean getRandomRoute() {
|
||||
return this.randomRoute;
|
||||
}
|
||||
public void setRandomRoute(boolean randomRoute) {
|
||||
this.randomRoute = randomRoute;
|
||||
}
|
||||
public File getApplicationDataAsFile() {
|
||||
return applicationDataAsFile;
|
||||
}
|
||||
public void setApplicationData(File archive) throws Exception {
|
||||
Assert.isLegal(this.applicationDataAsFile==null, "Can only set this once");
|
||||
this.applicationDataAsFile=archive;
|
||||
}
|
||||
public boolean isNoStart() {
|
||||
return noStart;
|
||||
}
|
||||
public void setNoStart(boolean noStart) {
|
||||
this.noStart = noStart;
|
||||
}
|
||||
public String getHealthCheckType() {
|
||||
if (healthCheckType==null) {
|
||||
return DeploymentProperties.DEFAULT_HEALTH_CHECK_TYPE;
|
||||
}
|
||||
return healthCheckType;
|
||||
}
|
||||
public void setHealthCheckType(String healthCheckType) {
|
||||
this.healthCheckType = healthCheckType;
|
||||
}
|
||||
public List<String> getRoutes() {
|
||||
return routes;
|
||||
}
|
||||
public void setRoutes(Collection<String> routes) {
|
||||
this.routes = routes == null ? ImmutableList.of() : ImmutableList.copyOf(routes);
|
||||
}
|
||||
public void setRoutes(String... routes) {
|
||||
setRoutes(ImmutableList.copyOf(routes));
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CFPushArguments [appName=" + appName + ", routes=" + routes + ", memory=" + memory + ", diskQuota="
|
||||
+ diskQuota + ", timeout=" + timeout + ", buildpack=" + buildpack + ", command=" + command + ", stack="
|
||||
+ stack + ", env=" + env + ", instances=" + instances + ", services=" + services + ", noStart="
|
||||
+ noStart + ", healthCheckType="+ healthCheckType+ ", randomRoute="+ randomRoute+" ]";
|
||||
}
|
||||
|
||||
public void setHealthCheckHttpEndpoint(String healthCheckHttpEndpoint) {
|
||||
this.healthCheckHttpEndpoint = healthCheckHttpEndpoint;
|
||||
}
|
||||
|
||||
public String getHealthCheckHttpEndpoint() {
|
||||
return this.healthCheckHttpEndpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
//This used to do something more useful, we kept it for now to avoid having to
|
||||
// change a lot of code. But calling `close` is no longer needed and does nothing.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.client.v2;
|
||||
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
|
||||
public class CFRoute {
|
||||
|
||||
public static final int NO_PORT = -1;
|
||||
public static final String EMPTY_ROUTE = "";
|
||||
|
||||
final private String domain;
|
||||
final private String host;
|
||||
final private String path;
|
||||
final private int port;
|
||||
final private String fullRoute;
|
||||
|
||||
CFRoute(String domain, String host, String path, int port, String fullRoute) {
|
||||
super();
|
||||
this.domain = domain;
|
||||
this.host = host;
|
||||
this.path = path;
|
||||
this.port = port;
|
||||
this.fullRoute = fullRoute;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
return fullRoute;
|
||||
}
|
||||
|
||||
public void validate() throws Exception {
|
||||
if (!StringUtil.hasText(getDomain())) {
|
||||
throw ExceptionUtil.coreException("Invalid route: No domain set.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CFRoute [domain=" + domain + ", host=" + host + ", path=" + path + ", port=" + port +"]";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((domain == null) ? 0 : domain.hashCode());
|
||||
result = prime * result + ((fullRoute == null) ? 0 : fullRoute.hashCode());
|
||||
result = prime * result + ((host == null) ? 0 : host.hashCode());
|
||||
result = prime * result + ((path == null) ? 0 : path.hashCode());
|
||||
result = prime * result + port;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CFRoute other = (CFRoute) obj;
|
||||
if (domain == null) {
|
||||
if (other.domain != null)
|
||||
return false;
|
||||
} else if (!domain.equals(other.domain))
|
||||
return false;
|
||||
if (fullRoute == null) {
|
||||
if (other.fullRoute != null)
|
||||
return false;
|
||||
} else if (!fullRoute.equals(other.fullRoute))
|
||||
return false;
|
||||
if (host == null) {
|
||||
if (other.host != null)
|
||||
return false;
|
||||
} else if (!host.equals(other.host))
|
||||
return false;
|
||||
if (path == null) {
|
||||
if (other.path != null)
|
||||
return false;
|
||||
} else if (!path.equals(other.path))
|
||||
return false;
|
||||
if (port != other.port)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static CFRouteBuilder builder() {
|
||||
return new CFRouteBuilder();
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 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.client.v2;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.cloudfoundry.operations.routes.Route;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCloudDomain;
|
||||
import org.springframework.ide.eclipse.boot.util.Log;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
|
||||
public class CFRouteBuilder {
|
||||
private String domain;
|
||||
private String host;
|
||||
private String path;
|
||||
private int port = CFRoute.NO_PORT;
|
||||
private String fullRoute;
|
||||
|
||||
public CFRoute build() {
|
||||
return new CFRoute(this.domain, this.host, this.path, this.port, this.fullRoute);
|
||||
}
|
||||
|
||||
public CFRouteBuilder domain(String domain) {
|
||||
this.domain = domain;
|
||||
// may seem like the more ideal place is to build the full route when
|
||||
// building the route, rather than repeating
|
||||
// the process each time a domain, host, path or port value is set
|
||||
// but the "from" option should be allowed to overwrite the full route
|
||||
// as well since it already
|
||||
// has the full value. Therefore re-construct the full value if the
|
||||
// route is being built piece by piece, but not in from
|
||||
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CFRouteBuilder host(String host) {
|
||||
this.host = host;
|
||||
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CFRouteBuilder path(String path) {
|
||||
this.path = path;
|
||||
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CFRouteBuilder port(int port) {
|
||||
this.port = port;
|
||||
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CFRouteBuilder from(Route route) {
|
||||
// Route doesn't seem to have API to get a port
|
||||
this.port = CFRoute.NO_PORT;
|
||||
this.domain = route.getDomain();
|
||||
this.host = route.getHost();
|
||||
this.path = route.getPath();
|
||||
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link CFRoute} given a desiredUrl. This does NOT validate, and
|
||||
* will attempt to build a route the best way it can given the desiredUrl.
|
||||
* External components, like the CF Java client, can then validate the
|
||||
* CFRoute.
|
||||
*
|
||||
* @param desiredUrl
|
||||
* @param domains
|
||||
* @return this builder
|
||||
*/
|
||||
public CFRouteBuilder from(String desiredUrl, Collection<String> domains) {
|
||||
|
||||
|
||||
//If it is empty or null, there is nothing to build. However, be sure that the
|
||||
// full route value is non-null, even if the "components" may be null
|
||||
if (!StringUtil.hasText(desiredUrl)) {
|
||||
this.fullRoute = CFRoute.EMPTY_ROUTE;
|
||||
return this;
|
||||
} else {
|
||||
// Be sure to set the full route.
|
||||
this.fullRoute = desiredUrl;
|
||||
}
|
||||
|
||||
// Based on CLI cf/actors/routes.go and testing CLI directly with
|
||||
// different "routes" values:
|
||||
// 1. Paths is not allowed in TCP route (valid TCP route:
|
||||
// "tcp.spring.io:8888")
|
||||
// 2. Ports are not allowed in HTTP route (valid HTTP route:
|
||||
// "myapps.cfapps.io/pathToApp/home")
|
||||
// 3. Schemes (e.g. "http://") are not allowed in routes values.
|
||||
// Anything that has a ":" is assumed to be TCP route followed by a port
|
||||
// 4. Route can just be domain, or host and domain
|
||||
//
|
||||
// Therefore, routes values cannot be treated as URIs or URLs, but a
|
||||
// combination of domain, host, path and port
|
||||
// NOTE: The validation above doesn't need to take place here. The
|
||||
// client or CF will validate correct combinations of routes.
|
||||
// However, We may want to implement similar
|
||||
// validation to the CF manifest editor though.
|
||||
|
||||
String matchedHost = null;
|
||||
String hostAndDomain = null;
|
||||
|
||||
// Split into hostDomain segment, port and path
|
||||
int slashIndex = desiredUrl.indexOf('/');
|
||||
if (slashIndex >= 0) {
|
||||
hostAndDomain = desiredUrl.substring(0, slashIndex);
|
||||
String tempPath = desiredUrl.substring(slashIndex);
|
||||
// Do not set empty strings. If there is no path, then it should be
|
||||
// null
|
||||
if (StringUtil.hasText(tempPath)) {
|
||||
this.path = tempPath;
|
||||
}
|
||||
} else {
|
||||
hostAndDomain = desiredUrl;
|
||||
}
|
||||
|
||||
// CF Route builder does not validate, so don't allow exceptions to
|
||||
// prevent parsing of the route. The builder should attempt to build
|
||||
// a route the best way it can, even if it may have invalid information.
|
||||
// This allows external participants, like the CF Java client, to
|
||||
// perform validation
|
||||
try {
|
||||
String[] portSegments = hostAndDomain.split(":");
|
||||
if (portSegments.length == 2) {
|
||||
hostAndDomain = portSegments[0];
|
||||
this.port = Integer.parseInt(portSegments[1]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
this.domain = findDomain(hostAndDomain, domains);
|
||||
|
||||
if (this.domain != null) {
|
||||
matchedHost = hostAndDomain.substring(0, hostAndDomain.length() - this.domain.length());
|
||||
if (matchedHost.endsWith(".")) {
|
||||
matchedHost = matchedHost.substring(0, matchedHost.length() - 1);
|
||||
}
|
||||
|
||||
// Don't set empty strings
|
||||
if (StringUtil.hasText(matchedHost)) {
|
||||
this.host = matchedHost;
|
||||
}
|
||||
} else {
|
||||
// Do a basic split on '.', where first segment is the host, and the
|
||||
// rest domain
|
||||
int firstDotIndex = hostAndDomain.indexOf('.');
|
||||
if (firstDotIndex >= 0) {
|
||||
String tempDomain = hostAndDomain.substring(firstDotIndex + 1);
|
||||
// Don't set empty strings
|
||||
if (StringUtil.hasText(tempDomain)) {
|
||||
this.domain = tempDomain;
|
||||
}
|
||||
|
||||
String tempHost = hostAndDomain.substring(0, firstDotIndex);
|
||||
if (StringUtil.hasText(tempHost)) {
|
||||
this.host = tempHost;
|
||||
}
|
||||
} else {
|
||||
if (StringUtil.hasText(hostAndDomain)) {
|
||||
this.host = hostAndDomain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public static String findDomain(String hostDomain, Collection<String> domains) {
|
||||
if (hostDomain == null) {
|
||||
return null;
|
||||
}
|
||||
// find exact match
|
||||
for (String name : domains) {
|
||||
if (hostDomain.equals(name)) {
|
||||
return hostDomain;
|
||||
}
|
||||
}
|
||||
// Otherwise split on the first "." and try again
|
||||
if (hostDomain.indexOf(".") >= 0 && hostDomain.indexOf(".") + 1 < hostDomain.length()) {
|
||||
String remaining = hostDomain.substring(hostDomain.indexOf(".") + 1, hostDomain.length());
|
||||
return findDomain(remaining, domains);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic building of a full route value. It performs no validation, just
|
||||
* builds based on whether the parameter are set
|
||||
*
|
||||
* @param host
|
||||
* @param domain
|
||||
* @param path
|
||||
* @param port
|
||||
* @return Route value build with the given components. Always returns a non-null route. Empty route if no arguments are passed.
|
||||
*/
|
||||
public static String buildRouteVal(String host, String domain, String path, int port) {
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (StringUtil.hasText(host)) {
|
||||
builder.append(host);
|
||||
}
|
||||
|
||||
if (StringUtil.hasText(domain)) {
|
||||
if (StringUtil.hasText(host)) {
|
||||
builder.append('.');
|
||||
}
|
||||
builder.append(domain);
|
||||
}
|
||||
|
||||
if (port != CFRoute.NO_PORT) {
|
||||
builder.append(':');
|
||||
builder.append(Integer.toString(port));
|
||||
}
|
||||
|
||||
if (StringUtil.hasText(path)) {
|
||||
if (!path.startsWith("/")) {
|
||||
builder.append('/');
|
||||
}
|
||||
builder.append(path);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public CFRouteBuilder from(String desiredUrl, List<CFCloudDomain> cloudDomains) {
|
||||
List<String> domains = cloudDomains
|
||||
.stream()
|
||||
.map(CFCloudDomain::getName)
|
||||
.collect(Collectors.toList());
|
||||
return from(desiredUrl, domains);
|
||||
}
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.cloudfoundry.client.v2.buildpacks.BuildpackResource;
|
||||
import org.cloudfoundry.operations.applications.ApplicationDetail;
|
||||
import org.cloudfoundry.operations.applications.ApplicationSummary;
|
||||
import org.cloudfoundry.operations.applications.InstanceDetail;
|
||||
import org.cloudfoundry.operations.domains.Domain;
|
||||
import org.cloudfoundry.operations.domains.Status;
|
||||
import org.cloudfoundry.operations.organizations.OrganizationSummary;
|
||||
import org.cloudfoundry.operations.services.ServiceInstance;
|
||||
import org.cloudfoundry.operations.services.ServiceInstanceType;
|
||||
import org.cloudfoundry.operations.spaces.SpaceSummary;
|
||||
import org.cloudfoundry.operations.stacks.Stack;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFAppState;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFApplication;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFApplicationDetail;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFBuildpack;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCloudDomain;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFDomainType;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFInstanceState;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFInstanceStats;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFOrganization;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFServiceInstance;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFSpace;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFStack;
|
||||
import org.springframework.ide.eclipse.boot.util.Log;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Various helper methods to 'wrap' objects returned by CF client into
|
||||
* our own types, so that we do not directly expose library types to our
|
||||
* code.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class CFWrappingV2 {
|
||||
|
||||
public static CFBuildpack wrap(BuildpackResource rsrc) {
|
||||
String name = rsrc.getEntity().getName();
|
||||
return new CFBuildpack() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CFApplicationDetail wrap(ApplicationDetail details, ApplicationExtras extras) {
|
||||
if (details!=null) {
|
||||
List<CFInstanceStats> instances = ImmutableList.copyOf(
|
||||
details.getInstanceDetails()
|
||||
.stream()
|
||||
.map(CFWrappingV2::wrap)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
CFApplicationSummaryData summary = wrapSummary(details, extras);
|
||||
return new CFApplicationDetailData(
|
||||
summary,
|
||||
instances
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CFStack wrap(Stack stack) {
|
||||
if (stack!=null) {
|
||||
String name = stack.getName();
|
||||
return new CFStack() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CFStack("+name+")";
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CFApplicationDetail wrap(
|
||||
CFApplicationSummaryData summary,
|
||||
ApplicationDetail details
|
||||
) {
|
||||
List<CFInstanceStats> instanceDetails = ImmutableList.copyOf(
|
||||
details
|
||||
.getInstanceDetails()
|
||||
.stream()
|
||||
.map(CFWrappingV2::wrap)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
return new CFApplicationDetailData(summary, instanceDetails);
|
||||
}
|
||||
|
||||
public static CFCloudDomain wrap(Domain domain) {
|
||||
if (domain!=null) {
|
||||
return new CFCloudDomainData(
|
||||
domain.getName(),
|
||||
CFWrappingV2.wrapDomainType(domain.getType()),
|
||||
CFWrappingV2.wrap(domain.getStatus())
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CFDomainStatus wrap(Status status) {
|
||||
if (status!=null) {
|
||||
return CFDomainStatus.valueOf(status.name());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CFDomainType wrapDomainType(String type) {
|
||||
if (type!=null) {
|
||||
return CFDomainType.valueOf(type.toUpperCase());
|
||||
}
|
||||
return CFDomainType.HTTP;
|
||||
}
|
||||
|
||||
public static CFInstanceStats wrap(InstanceDetail instanceDetail) {
|
||||
return new CFInstanceStats() {
|
||||
@Override
|
||||
public CFInstanceState getState() {
|
||||
try {
|
||||
return CFInstanceState.valueOf(instanceDetail.getState());
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return CFInstanceState.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ""+getState();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static CFApplicationSummaryData wrapSummary(ApplicationDetail app, ApplicationExtras extras) {
|
||||
CFAppState state;
|
||||
try {
|
||||
state = CFAppState.valueOf(app.getRequestedState());
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
state = CFAppState.UNKNOWN;
|
||||
}
|
||||
|
||||
return new CFApplicationSummaryData(
|
||||
app.getName(),
|
||||
app.getInstances(),
|
||||
app.getRunningInstances(),
|
||||
app.getMemoryLimit(),
|
||||
UUID.fromString(app.getId()),
|
||||
app.getUrls(),
|
||||
state,
|
||||
app.getDiskQuota(),
|
||||
extras
|
||||
);
|
||||
}
|
||||
|
||||
public static CFApplication wrap(ApplicationSummary app, ApplicationExtras extras) {
|
||||
CFAppState state;
|
||||
try {
|
||||
state = CFAppState.valueOf(app.getRequestedState());
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
state = CFAppState.UNKNOWN;
|
||||
}
|
||||
|
||||
return new CFApplicationSummaryData(
|
||||
app.getName(),
|
||||
app.getInstances(),
|
||||
app.getRunningInstances(),
|
||||
app.getMemoryLimit(),
|
||||
UUID.fromString(app.getId()),
|
||||
app.getUrls(),
|
||||
state,
|
||||
app.getDiskQuota(),
|
||||
extras
|
||||
);
|
||||
}
|
||||
|
||||
public static CFServiceInstance wrap(final ServiceInstance service) {
|
||||
return new CFServiceInstance() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return service.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlan() {
|
||||
return service.getPlan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDashboardUrl() {
|
||||
return service.getDashboardUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getService() {
|
||||
if (service.getType()==ServiceInstanceType.USER_PROVIDED) {
|
||||
return "user-provided";
|
||||
} else {
|
||||
return service.getService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return service.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDocumentationUrl() {
|
||||
return service.getDocumentationUrl();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CFAppState wrapAppState(String s) {
|
||||
try {
|
||||
return CFAppState.valueOf(s);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return CFAppState.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public static CFSpace wrap(OrganizationSummary org, SpaceSummary space) {
|
||||
return new CFSpace() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return space.getName();
|
||||
}
|
||||
@Override
|
||||
public CFOrganization getOrganization() {
|
||||
return wrap(org);
|
||||
}
|
||||
@Override
|
||||
public UUID getGuid() {
|
||||
return UUID.fromString(space.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CFSpace("+org.getName()+" / "+getName()+")";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CFOrganization wrap(OrganizationSummary org) {
|
||||
return new CFOrganization() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return org.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getGuid() {
|
||||
return UUID.fromString(org.getId());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CFBuildpack buildpack(String name) {
|
||||
return new CFBuildpack() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.client.v2;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cloudfoundry.client.CloudFoundryClient;
|
||||
import org.cloudfoundry.client.v2.info.GetInfoRequest;
|
||||
import org.cloudfoundry.client.v2.info.GetInfoResponse;
|
||||
import org.cloudfoundry.reactor.DefaultConnectionContext;
|
||||
import org.cloudfoundry.reactor.ProxyConfiguration;
|
||||
import org.cloudfoundry.reactor.TokenProvider;
|
||||
import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient;
|
||||
import org.cloudfoundry.reactor.doppler.ReactorDopplerClient;
|
||||
import org.cloudfoundry.reactor.tokenprovider.OneTimePasscodeTokenProvider;
|
||||
import org.cloudfoundry.reactor.tokenprovider.PasswordGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.tokenprovider.RefreshTokenGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.uaa.ReactorUaaClient;
|
||||
import org.eclipse.core.net.proxy.IProxyData;
|
||||
import org.eclipse.core.net.proxy.IProxyService;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCredentials;
|
||||
import org.springframework.ide.eclipse.boot.util.Log;
|
||||
import org.springsource.ide.eclipse.commons.frameworks.core.util.StringUtils;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* TODO: Remove this class when the 'thread leak bug' in V2 client is fixed.
|
||||
*
|
||||
* At the moment each time {@link SpringCloudFoundryClient} is create a threadpool
|
||||
* is created by the client and it is never cleaned up. The only way we have
|
||||
* to mitigate this leak is to try and create as few clients as possible.
|
||||
* <p>
|
||||
* So we have a permanent cache of clients here that is reused.
|
||||
* <p>
|
||||
* When the bug is fixed then this should no longer be necessary and we can removed this cache
|
||||
* and just create the client as needed.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class CloudFoundryClientCache {
|
||||
|
||||
public class CFClientProvider {
|
||||
|
||||
final DefaultConnectionContext connection;
|
||||
final TokenProvider tokenProvider;
|
||||
|
||||
//Note: the three client objects below are 'stateless' wrappers and it would be
|
||||
// fine to recreate as needed instead of store them
|
||||
|
||||
final CloudFoundryClient client;
|
||||
final ReactorUaaClient uaaClient;
|
||||
final ReactorDopplerClient doppler;
|
||||
final Mono<GetInfoResponse> info;
|
||||
|
||||
private ProxyConfiguration getProxy(String host) {
|
||||
try {
|
||||
if (StringUtils.hasText(host)) {
|
||||
URL url = new URL("https://"+host);
|
||||
// In certain cases, the activator would have stopped and the plugin may
|
||||
// no longer be available. Usually onl happens on shutdown.
|
||||
BootDashActivator plugin = BootDashActivator.getDefault();
|
||||
if (plugin != null) {
|
||||
IProxyService proxyService = plugin.getProxyService();
|
||||
if (proxyService != null) {
|
||||
IProxyData[] selectedProxies = proxyService.select(url.toURI());
|
||||
|
||||
// No proxy configured or not found
|
||||
if (selectedProxies == null || selectedProxies.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IProxyData data = selectedProxies[0];
|
||||
int proxyPort = data.getPort();
|
||||
String proxyHost = data.getHost();
|
||||
String user = data.getUserId();
|
||||
String password = data.getPassword();
|
||||
if (proxyHost!=null) {
|
||||
return ProxyConfiguration.builder()
|
||||
.host(proxyHost)
|
||||
.port(proxyPort==-1?Optional.empty():Optional.of(proxyPort))
|
||||
.username(Optional.ofNullable(user))
|
||||
.password(Optional.ofNullable(password))
|
||||
.build();
|
||||
// return proxyHost != null ? new HttpProxyConfiguration(proxyHost, proxyPort,
|
||||
// data.isRequiresAuthentication(), user, password) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public CFClientProvider(Params params) {
|
||||
long sslTimeout = Long.getLong("sts.bootdash.cf.client.ssl.handshake.timeout", 60); //TODO: make a preference for this?
|
||||
Optional<Boolean> keepAlive = getBooleanSystemProp("http.keepAlive");
|
||||
debug("cf client keepAlive = "+keepAlive);
|
||||
connection = DefaultConnectionContext.builder()
|
||||
.proxyConfiguration(Optional.ofNullable(getProxy(params.host)))
|
||||
.apiHost(params.host)
|
||||
.sslHandshakeTimeout(Duration.ofSeconds(sslTimeout))
|
||||
.keepAlive(keepAlive)
|
||||
.skipSslValidation(params.skipSsl)
|
||||
.build();
|
||||
|
||||
tokenProvider = createTokenProvider(params);
|
||||
|
||||
client = ReactorCloudFoundryClient.builder()
|
||||
.connectionContext(connection)
|
||||
.tokenProvider(tokenProvider)
|
||||
.build();
|
||||
|
||||
uaaClient = ReactorUaaClient.builder()
|
||||
.connectionContext(connection)
|
||||
.tokenProvider(tokenProvider)
|
||||
.build();
|
||||
|
||||
doppler = ReactorDopplerClient.builder()
|
||||
.connectionContext(connection)
|
||||
.tokenProvider(tokenProvider)
|
||||
.build();
|
||||
|
||||
// Cache CF client info - workaround for https://www.pivotaltracker.com/story/show/158741609
|
||||
info = client.info().get(GetInfoRequest.builder().build()).cache();
|
||||
}
|
||||
|
||||
private TokenProvider createTokenProvider(Params params) {
|
||||
CFCredentials creds = params.credentials;
|
||||
switch (creds.getType()) {
|
||||
case PASSWORD:
|
||||
return PasswordGrantTokenProvider.builder()
|
||||
.username(params.username)
|
||||
.password(creds.getSecret())
|
||||
.build();
|
||||
case REFRESH_TOKEN:
|
||||
return RefreshTokenGrantTokenProvider.builder()
|
||||
.token(creds.getSecret())
|
||||
.build();
|
||||
case TEMPORARY_CODE:
|
||||
return OneTimePasscodeTokenProvider.builder()
|
||||
.passcode(creds.getSecret())
|
||||
.build();
|
||||
default:
|
||||
throw new IllegalStateException("BUG! Missing switch case?");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Boolean> getBooleanSystemProp(String name) {
|
||||
String str = System.getProperty(name);
|
||||
if (str!=null) {
|
||||
return Optional.of(Boolean.valueOf(str));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static void debug(String string) {
|
||||
if (DEBUG) {
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Params {
|
||||
public final String username;
|
||||
public final CFCredentials credentials;
|
||||
public final String host;
|
||||
public final boolean skipSsl;
|
||||
public Params(String username, CFCredentials credentials, String host, boolean skipSsl) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.credentials = credentials;
|
||||
this.host = host;
|
||||
this.skipSsl = skipSsl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Params [username=" + username + ", host=" + host + ", skipSsl=" + skipSsl
|
||||
+ "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((host == null) ? 0 : host.hashCode());
|
||||
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
|
||||
result = prime * result + (skipSsl ? 1231 : 1237);
|
||||
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;
|
||||
Params other = (Params) obj;
|
||||
if (host == null) {
|
||||
if (other.host != null)
|
||||
return false;
|
||||
} else if (!host.equals(other.host))
|
||||
return false;
|
||||
if (credentials == null) {
|
||||
if (other.credentials != null)
|
||||
return false;
|
||||
} else if (!credentials.equals(other.credentials))
|
||||
return false;
|
||||
if (skipSsl != other.skipSsl)
|
||||
return false;
|
||||
if (username == null) {
|
||||
if (other.username != null)
|
||||
return false;
|
||||
} else if (!username.equals(other.username))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Params, CFClientProvider> cache = new HashMap<>();
|
||||
|
||||
private int clientCount = 0;
|
||||
|
||||
public synchronized CFClientProvider getOrCreate(String username, CFCredentials credentials, String host, boolean skipSsl) {
|
||||
Params params = new Params(username, credentials, host, skipSsl);
|
||||
CFClientProvider client = cache.get(params);
|
||||
if (client==null) {
|
||||
clientCount++;
|
||||
debug("Creating client ["+clientCount+"]: "+params);
|
||||
cache.put(params, client = create(params));
|
||||
} else {
|
||||
debug("Reusing client ["+clientCount+"]: "+params);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
protected CFClientProvider create(Params params) {
|
||||
return new CFClientProvider(params);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.springframework.ide.eclipse.boot.dash.cf.client.CFClientParams;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.ClientRequests;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CloudFoundryClientFactory;
|
||||
|
||||
public class DefaultCloudFoundryClientFactoryV2 extends CloudFoundryClientFactory {
|
||||
|
||||
public static final DefaultCloudFoundryClientFactoryV2 INSTANCE = new DefaultCloudFoundryClientFactoryV2();
|
||||
|
||||
/**
|
||||
* Use 'INSTANCE' constant instead. This class is a singleton.
|
||||
*/
|
||||
private DefaultCloudFoundryClientFactoryV2() {}
|
||||
|
||||
private CloudFoundryClientCache clientFactory = new CloudFoundryClientCache();
|
||||
|
||||
@Override
|
||||
public ClientRequests getClient(CFClientParams params) {
|
||||
return new DefaultClientRequestsV2(clientFactory, params);
|
||||
}
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.client.v2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ReactorUtils {
|
||||
|
||||
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(45); // reflects default timeout of Mono.block in reactor 2.x.
|
||||
public static boolean DUMP_STACK_ON_TIMEOUT = false;
|
||||
|
||||
/**
|
||||
* Convert a {@link CancelationToken} into a Mono that raises
|
||||
* an {@link OperationCanceledException} when the token is canceled.
|
||||
*/
|
||||
public static <T> Mono<T> toMono(CancelationToken cancelToken) {
|
||||
return Mono.delay(Duration.ofSeconds(1))
|
||||
.flatMap((ping) ->
|
||||
cancelToken.isCanceled()
|
||||
? Mono.<T>error(new OperationCanceledException())
|
||||
: Mono.empty()
|
||||
)
|
||||
.repeatWhenEmpty((x) -> x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to Mono.get but logs a more traceable version of the exception to Eclipse's error
|
||||
* log before 'rethrowing' it.
|
||||
* <p>
|
||||
* This is useful because the actual exception is pretty hard to trace. It doesn't even 'point'
|
||||
* to the line where 'get' was called.
|
||||
*/
|
||||
public static <T> T get(Mono<T> mono) throws Exception {
|
||||
try {
|
||||
return mono.block(DEFAULT_TIMEOUT);
|
||||
} catch (Exception e) {
|
||||
dumpStacks();
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to Mono.get but logs a more traceable version of the exception to Eclipse's error
|
||||
* log before 'rethrowing' it.
|
||||
* <p>
|
||||
* This is useful because the actual exception is pretty hard to trace. It doesn't even 'point'
|
||||
* to the line where 'get' was called.
|
||||
*/
|
||||
public static <T> T get(Duration timeout, CancelationToken cancelationToken, Mono<T> mono) throws Exception {
|
||||
try {
|
||||
return Mono.first(mono, toMono(cancelationToken))
|
||||
.onErrorResume(errorFilter(cancelationToken))
|
||||
.block(timeout);
|
||||
} catch (Exception e) {
|
||||
//dumpStacks();
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> List<T> get(Duration t, Mono<List<T>> m) throws IOException {
|
||||
try {
|
||||
return m.block(t);
|
||||
} catch (Exception e) {
|
||||
dumpStacks();
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpStacks() {
|
||||
if (DUMP_STACK_ON_TIMEOUT) {
|
||||
System.out.println(getStackDumps().toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A 'filter' to use as a Mono.otherwise hanlder. It transforms any exception into {@link OperationCanceledException}
|
||||
* when cancelationToken has been canceled.
|
||||
*/
|
||||
private static <T> Function<Throwable, Mono<T>> errorFilter(CancelationToken cancelationToken) {
|
||||
return (Throwable e) -> cancelationToken.isCanceled()?Mono.error(new OperationCanceledException()):Mono.error(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated because this is really the same as Mono.justOrEmpty, so use that instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> Mono<T> just(T it) {
|
||||
return it == null ? Mono.empty() : Mono.just(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A function that can be passed to Mono.otherwise to convert a specific exception type into
|
||||
* Mono.empty().
|
||||
*/
|
||||
public static <T> Function<Throwable, Mono<T>> suppressException(Class<? extends Throwable> exceptionType) {
|
||||
return (Throwable caught) -> {
|
||||
if (exceptionType.isAssignableFrom(caught.getClass())) {
|
||||
return Mono.empty();
|
||||
} else {
|
||||
return Mono.error(caught);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Mono<Void> that executes a given number of Mono<Void> one after the
|
||||
* other.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Mono<Void> sequence(Mono<Void>... tasks) {
|
||||
Mono<Void> seq = Mono.empty();
|
||||
for (Mono<Void> t : tasks) {
|
||||
seq = seq.then(t);
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a bunch of mono in parallel. All monos are executed to completion (rather than canceled early
|
||||
* when one of them fails)
|
||||
* <p>
|
||||
* When at least one operation has failed then, upon completion or failure of the last Mono we guarantee that at least
|
||||
* one of the exceptions is propagated.
|
||||
*/
|
||||
public static Mono<Void> safeMerge(Flux<Mono<Void>> operations, int concurrency) {
|
||||
AtomicReference<Throwable> failure = new AtomicReference<>(null);
|
||||
return Flux.merge(
|
||||
operations
|
||||
.map((Mono<Void> op) -> {
|
||||
return op.onErrorResume((e) -> {
|
||||
failure.compareAndSet(null, e);
|
||||
return Mono.empty();
|
||||
});
|
||||
}),
|
||||
concurrency //limit concurrency otherwise troubles (flooding/choking request broker?)
|
||||
)
|
||||
.then(Mono.defer(() -> {
|
||||
Throwable error = failure.get();
|
||||
if (error!=null) {
|
||||
return Mono.error(error);
|
||||
} else {
|
||||
return Mono.empty();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a timestamp to each element in a Stream
|
||||
*/
|
||||
public static <T> Flux<Tuple2<T,Long>> timestamp(Flux<T> stream) {
|
||||
return stream.map((e) -> Tuples.of(e, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the elements in a flux in a moving time window. I.e. this assumes element order may be
|
||||
* scrambled but the scrambling has a certain 'time localilty' to it. So we only need to consider
|
||||
* sorting of elements that arrive 'close to eachother'.
|
||||
* <p>
|
||||
* WARNING: The returned flux is intended for a single subscriber. It only maintains a
|
||||
* single buffer for sorting stream elements. This buffer is consumed when elements
|
||||
* are released to any subscriber. Therefore if one subscriber received a element it is gone
|
||||
* from the buffer and will not be delivered to the other subscribers.
|
||||
*
|
||||
* @param stream The stream to be sorted
|
||||
* @param comparator Compare function to sort with
|
||||
* @param bufferTime The 'window' of time beyond which we don't need to compare elements.
|
||||
*/
|
||||
public static <T> Flux<T> sort(Flux<T> stream, Comparator<T> comparator, Duration bufferTime) {
|
||||
|
||||
class SorterAccumulator {
|
||||
|
||||
final PriorityQueue<Tuple2<T, Long>> holdingPen = new PriorityQueue<>((Tuple2<T, Long> o1, Tuple2<T, Long> o2) -> {
|
||||
return comparator.compare(o1.getT1(), o2.getT1());
|
||||
});
|
||||
|
||||
final Flux<T> released = Flux.fromIterable(() -> new Iterator<T>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
Tuple2<T, Long> nxt;
|
||||
synchronized (holdingPen) {
|
||||
nxt = holdingPen.peek();
|
||||
}
|
||||
return nxt!=null && isOldEnough(nxt);
|
||||
}
|
||||
|
||||
private boolean isOldEnough(Tuple2<T, Long> nxt) {
|
||||
long age = System.currentTimeMillis() - nxt.getT2();
|
||||
return age > bufferTime.toMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
synchronized (holdingPen) {
|
||||
return holdingPen.remove().getT1();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public SorterAccumulator next(Flux<Tuple2<T, Long>> window) {
|
||||
window.subscribe((e) -> {
|
||||
synchronized (holdingPen) {
|
||||
holdingPen.add(e);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Flux<T> getReleased() {
|
||||
return released;
|
||||
}
|
||||
|
||||
public Publisher<? extends T> drain() {
|
||||
return Flux.fromIterable(holdingPen)
|
||||
.map(Tuple2::getT1);
|
||||
}
|
||||
}
|
||||
|
||||
SorterAccumulator sorter = new SorterAccumulator();
|
||||
return timestamp(stream)
|
||||
.window(bufferTime)
|
||||
.scan(sorter, SorterAccumulator::next)
|
||||
.concatMap(SorterAccumulator::getReleased)
|
||||
.concatWith(sorter.drain());
|
||||
}
|
||||
|
||||
protected static StringBuffer getStackDumps() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
|
||||
for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
|
||||
sb.append(entry.getKey().toString());
|
||||
sb.append("\n");
|
||||
for (StackTraceElement element : entry.getValue()) {
|
||||
sb.append(" ");
|
||||
sb.append(element.toString());
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Connect a mono to a CompletableFuture so that the result of the mono
|
||||
* can be retrieved from the {@link CompletableFuture} by calling it's 'get'
|
||||
* method.
|
||||
*/
|
||||
public static <T> void completeWith(CompletableFuture<T> future, Mono<T> mono) {
|
||||
mono.doOnNext((T v) -> {
|
||||
future.complete(v);
|
||||
})
|
||||
.doOnError((Throwable e) -> {
|
||||
future.completeExceptionally(e);
|
||||
})
|
||||
.subscribeOn(Schedulers.elastic())
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
|
||||
|
||||
/**
|
||||
* This class is responsible for managing the debug strategies. It is also responsible for managing the life
|
||||
* cycle of process listeners abd other {@link Disposable}s that may be associated with a debug strategy and
|
||||
* should be disposed when the manager itself is disposed.
|
||||
* <p>
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class DebugStrategyManager implements Disposable {
|
||||
|
||||
|
||||
private DebugSupport strategy;
|
||||
private Disposable processTracker;
|
||||
|
||||
public DebugStrategyManager(List<DebugSupport> list, BootDashViewModel viewModel) {
|
||||
// At the moment there's only one supported debug strategy, in the future there may be more than one.
|
||||
// In that case this class may need be generalized to manage a collection of strategies somehow.
|
||||
Assert.isLegal(list.size()==1);
|
||||
this.strategy = list.get(0);
|
||||
this.processTracker = strategy.createProcessTracker(viewModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (this.processTracker!=null) {
|
||||
this.processTracker.dispose();
|
||||
this.processTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
public DebugSupport getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.debug;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.debug.core.ILaunch;
|
||||
import org.eclipse.debug.core.model.IDebugTarget;
|
||||
import org.eclipse.debug.core.model.IProcess;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.ops.Operation;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
|
||||
import org.springframework.ide.eclipse.boot.util.ProcessListenerAdapter;
|
||||
import org.springframework.ide.eclipse.boot.util.ProcessTracker;
|
||||
|
||||
/**
|
||||
* Abstract class that must be implemented to add debug support to a CF application.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public abstract class DebugSupport {
|
||||
|
||||
/**
|
||||
* Determine whether debugging can be supported (using the strategy impemented by this DebugSupport instance)
|
||||
*/
|
||||
public abstract boolean isSupported(CloudAppDashElement app);
|
||||
/**
|
||||
* If isSupported returns false than the support strategy may also return an explanation why the strategy is not
|
||||
* supported (e.g. PCF version too old, SSH support disabled etc.)
|
||||
*/
|
||||
public abstract String getNotSupportedMessage(CloudAppDashElement app);
|
||||
|
||||
/**
|
||||
* Creates operation that does whatever is needed to get debugger connected to the targetted app.
|
||||
*/
|
||||
public abstract Operation<?> createOperation(CloudAppDashElement app, String opName, UserInteractions ui, CancelationToken cancelToken);
|
||||
|
||||
/**
|
||||
* Called to allow debug support to muck around with environment variables so that it can
|
||||
* do things like add debugging options to 'JAVA_OPTS'.
|
||||
*/
|
||||
public abstract void setupEnvVars(Map<String, String> environmentVariables);
|
||||
|
||||
/**
|
||||
* Like setupEnvVars, but called when debugging is disabled. The debug strategy should try to
|
||||
* undo any changes it made to the env vars to enable debugging.
|
||||
*/
|
||||
public abstract void clearEnvVars(Map<String, String> environmentVariables);
|
||||
|
||||
/**
|
||||
* Determines whether debugger is currently attached to the targetted app.
|
||||
*/
|
||||
public abstract boolean isDebuggerAttached(CloudAppDashElement app);
|
||||
|
||||
/**
|
||||
* A debug strategy typically involves creating some type of launch that establishes
|
||||
* a debug connection. To be able to update the debug state in response to changes in
|
||||
* launches, its necessary to be able to determine what dashboard element corresponds to
|
||||
* a given launch. Therefore a debug strategy must implement this method.
|
||||
*
|
||||
* @return The corresponding CDE for a given launch, or null
|
||||
*/
|
||||
public abstract CloudAppDashElement getElementFor(ILaunch l, BootDashViewModel viewModel);
|
||||
|
||||
/**
|
||||
* Provides a process tracker. Subclasses may override if the default implementation is not suitable.
|
||||
* <p>
|
||||
* The process tracker is responsible to listen for changes in the Eclipse debug ui so it can make
|
||||
* bootdash elements 'debug' state update when processes and/or debug targets are created or terminated.
|
||||
*/
|
||||
public ProcessTracker createProcessTracker(final BootDashViewModel viewModel) {
|
||||
return new ProcessTracker(new ProcessListenerAdapter() {
|
||||
@Override
|
||||
public void debugTargetCreated(ProcessTracker tracker, IDebugTarget target) {
|
||||
handleStateChange(target.getLaunch(), "debugTargetCreated");
|
||||
}
|
||||
@Override
|
||||
public void debugTargetTerminated(ProcessTracker tracker, IDebugTarget target) {
|
||||
handleStateChange(target.getLaunch(), "debugTargetTerminated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTerminated(ProcessTracker tracker, IProcess process) {
|
||||
//Typically a debug strategy only needs to care about debugtargets, not IProcesses.
|
||||
// So nothing to do here.
|
||||
}
|
||||
@Override
|
||||
public void processCreated(ProcessTracker tracker, IProcess process) {
|
||||
//Typically a debug strategy only needs to care about debugtargets, not IProcesses.
|
||||
// So nothing to do here.
|
||||
}
|
||||
private void handleStateChange(ILaunch l, Object info) {
|
||||
CloudAppDashElement e = getElementFor(l, viewModel);
|
||||
if (e!=null) {
|
||||
BootDashModel model = e.getBootDashModel();
|
||||
model.notifyElementChanged(e, info);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.debug.core.ILaunchConfiguration;
|
||||
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
|
||||
import org.springframework.ide.eclipse.boot.launch.LaunchTabSelectionModel;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
public class SelectRunTargetLaunchTabModel extends LaunchTabSelectionModel<CloudFoundryRunTarget> {
|
||||
|
||||
// public static SelectProjectLaunchTabModel create() {
|
||||
// LiveVariable<IProject> project = new LiveVariable<IProject>();
|
||||
// ExistingBootProjectSelectionValidator validator = new ExistingBootProjectSelectionValidator(project);
|
||||
// return new SelectProjectLaunchTabModel(project, validator);
|
||||
// }
|
||||
|
||||
private BootDashViewModel context;
|
||||
|
||||
public SelectRunTargetLaunchTabModel(LiveVariable<CloudFoundryRunTarget> variable, LiveExpression<ValidationResult> validator, BootDashViewModel context) {
|
||||
super(variable, validator);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeFrom(ILaunchConfiguration conf) {
|
||||
selection.setValue(SshDebugLaunchConfigurationDelegate.getRunTarget(conf, context));
|
||||
getDirtyState().setValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performApply(ILaunchConfigurationWorkingCopy conf) {
|
||||
SshDebugLaunchConfigurationDelegate.setRunTarget(conf, selection.getValue());
|
||||
getDirtyState().setValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaults(ILaunchConfigurationWorkingCopy conf) {
|
||||
// if (choices.length>0) {
|
||||
// SshDebugLaunchConfigurationDelegate.setRunTarget(conf, choices[0]);
|
||||
// }
|
||||
}
|
||||
|
||||
public CloudFoundryRunTarget[] getChoices() {
|
||||
ImmutableSet<RunTarget> targets = context.getRunTargets().getValues();
|
||||
ArrayList<CloudFoundryRunTarget> interesting = new ArrayList<>(targets.size());
|
||||
for (RunTarget t : targets) {
|
||||
if (t instanceof CloudFoundryRunTarget) {
|
||||
interesting.add((CloudFoundryRunTarget) t);
|
||||
}
|
||||
}
|
||||
return interesting.toArray(new CloudFoundryRunTarget[interesting.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.NameableLabelProvider;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.DelegatingLaunchConfigurationTabSection;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.ILaunchConfigurationTabSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.ChooseOneSectionCombo;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.IPageWithSections;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SelectRunTargetLaunchTabSection {
|
||||
|
||||
public static ILaunchConfigurationTabSection create(IPageWithSections owner, SelectRunTargetLaunchTabModel model) {
|
||||
ChooseOneSectionCombo<CloudFoundryRunTarget> ui =
|
||||
new ChooseOneSectionCombo<CloudFoundryRunTarget>(owner, "Target", model, model.getChoices());
|
||||
ui.setLabelProvider(new NameableLabelProvider());
|
||||
return new DelegatingLaunchConfigurationTabSection(owner, model, ui);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,386 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.SubProgressMonitor;
|
||||
import org.eclipse.debug.core.ILaunch;
|
||||
import org.eclipse.debug.core.ILaunchConfiguration;
|
||||
import org.eclipse.debug.core.ILaunchConfigurationType;
|
||||
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
|
||||
import org.eclipse.debug.core.ILaunchManager;
|
||||
import org.eclipse.debug.core.model.IDebugTarget;
|
||||
import org.eclipse.debug.core.model.IProcess;
|
||||
import org.eclipse.jdt.internal.launching.LaunchingMessages;
|
||||
import org.eclipse.jdt.internal.launching.LaunchingPlugin;
|
||||
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
|
||||
import org.eclipse.jdt.launching.IVMConnector;
|
||||
import org.eclipse.jdt.launching.JavaRuntime;
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
import org.springframework.ide.eclipse.boot.core.BootActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.SshClientSupport;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.SshHost;
|
||||
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.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
|
||||
import org.springframework.ide.eclipse.boot.launch.AbstractBootLaunchConfigurationDelegate;
|
||||
import org.springframework.ide.eclipse.boot.launch.BootLaunchConfigurationDelegate;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.WaitFor;
|
||||
import org.springframework.ide.eclipse.boot.util.ProcessListenerAdapter;
|
||||
import org.springframework.ide.eclipse.boot.util.ProcessTracker;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class SshDebugLaunchConfigurationDelegate extends AbstractBootLaunchConfigurationDelegate {
|
||||
|
||||
public static final String TYPE_ID = "org.springframework.ide.eclipse.boot.dash.ssh.tunnel.launch";
|
||||
|
||||
private static final long DEBUG_CONNECT_TIMEOUT = 20000;
|
||||
public static final String RUN_TARGET = "ssh.debug.runtarget.id";
|
||||
public static final String APP_NAME = "ssh.debug.app.name";
|
||||
public static final String INSTANCE_IDX = "ssh.debug.app.instance";
|
||||
|
||||
private static BootDashViewModel getContext() {
|
||||
//TODO: it may be necessary to allow injecting this, for example via setting a threadlocal,
|
||||
// to make code more amenable to unit testing.
|
||||
//This method is here because LaunchConf delegates are created by eclipse debug framework and
|
||||
// so we can't easily inject a context object into it.
|
||||
//The only method that should be calling this is 'launch'. Everything else should be doing
|
||||
// the proper thing and pass in the model as parameter somehow.
|
||||
return BootDashActivator.getDefault().getModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(ILaunchConfiguration conf, String mode, ILaunch launch, IProgressMonitor mon)
|
||||
throws CoreException {
|
||||
conf = configureClassPathProviders(conf);
|
||||
Assert.isTrue(ILaunchManager.DEBUG_MODE.equals(mode));
|
||||
BootDashViewModel context = getContext();
|
||||
mon.beginTask("Establish SSH Debug Connection to "+getAppName(conf)+" on "+getRunTarget(conf, context), 4);
|
||||
CloudAppDashElement app = null;
|
||||
try {
|
||||
CloudFoundryRunTarget target = getRunTarget(conf, context);
|
||||
SshDebugSupport debugSupport = getDebugSupport(conf, context);
|
||||
|
||||
app = getApp(conf, context);
|
||||
|
||||
if (app!=null && target!=null && debugSupport.isSupported(app)) {
|
||||
//1: determine SSH tunnel parameters
|
||||
app.log("Fetching SSH tunnel parameters...");
|
||||
SshClientSupport sshInfo = target.getSshClientSupport();
|
||||
SshHost sshHost = sshInfo.getSshHost();
|
||||
String sshUser = sshInfo.getSshUser(app.getAppGuid(), getInstanceIndex(conf));
|
||||
String sshCode = sshInfo.getSshCode();
|
||||
int remotePort = debugSupport.getRemotePort();
|
||||
|
||||
app.log("SSH tunnel parameters:");
|
||||
app.log(" host: "+sshHost);
|
||||
app.log(" user: "+sshUser);
|
||||
app.log(" code: "+sshCode);
|
||||
app.log(" remote port: "+remotePort);
|
||||
mon.worked(1);
|
||||
|
||||
//2: create tunnel
|
||||
app.log("Creating tunnel...");
|
||||
SshTunnel tunnel = new SshTunnelImpl(sshHost, sshUser, sshCode, remotePort, app); //TODO: use SshTunnelFactory?
|
||||
|
||||
//3: connect debugger stuff
|
||||
app.log("Launching remote debug connector...");
|
||||
launchRemote(tunnel, conf, launch, new SubProgressMonitor(mon, 1));
|
||||
app.log("Launching remote debug connector... DONE");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (app!=null) {
|
||||
app.log("ERROR: "+ExceptionUtil.getMessage(e));
|
||||
}
|
||||
throw ExceptionUtil.coreException(e);
|
||||
} finally {
|
||||
mon.done();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getInstanceIndex(ILaunchConfiguration conf) {
|
||||
try {
|
||||
return conf.getAttribute(INSTANCE_IDX, 0);
|
||||
} catch (Exception e) {
|
||||
BootDashActivator.log(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private SshDebugSupport getDebugSupport(ILaunchConfiguration conf, BootDashViewModel context) {
|
||||
CloudAppDashElement app = getApp(conf, context);
|
||||
if (app!=null) {
|
||||
DebugSupport ds = app.getDebugSupport();
|
||||
if (ds instanceof DebugSupport) {
|
||||
return (SshDebugSupport) ds;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static String getAppName(ILaunchConfiguration conf) {
|
||||
return getString(conf, APP_NAME);
|
||||
}
|
||||
|
||||
public static CloudAppDashElement getApp(ILaunchConfiguration conf, BootDashViewModel context) {
|
||||
String appName = getAppName(conf);
|
||||
if (appName!=null) {
|
||||
BootDashModel section = context.getSectionByTargetId(getRunTargetId(conf));
|
||||
if (section instanceof CloudFoundryBootDashModel) {
|
||||
CloudFoundryBootDashModel cfmodel = (CloudFoundryBootDashModel) section;
|
||||
return cfmodel.getApplication(appName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void setAppName(ILaunchConfigurationWorkingCopy conf, String name) {
|
||||
if (name!=null) {
|
||||
conf.setAttribute(APP_NAME, name);
|
||||
} else {
|
||||
conf.removeAttribute(APP_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setRunTarget(ILaunchConfigurationWorkingCopy conf, CloudFoundryRunTarget target) {
|
||||
if (target!=null) {
|
||||
conf.setAttribute(RUN_TARGET, target.getId());
|
||||
} else {
|
||||
conf.removeAttribute(RUN_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getRunTargetId(ILaunchConfiguration conf) {
|
||||
String at = RUN_TARGET;
|
||||
return getString(conf, at);
|
||||
}
|
||||
|
||||
|
||||
protected static String getString(ILaunchConfiguration conf, String attName) {
|
||||
try {
|
||||
return conf.getAttribute(attName, (String)null);
|
||||
} catch (CoreException e) {
|
||||
BootDashActivator.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CloudFoundryRunTarget getRunTarget(ILaunchConfiguration conf, BootDashViewModel context) {
|
||||
try {
|
||||
String id = conf.getAttribute(RUN_TARGET, (String)null);
|
||||
if (id!=null) {
|
||||
RunTarget target = context.getRunTargetById(id);
|
||||
if (target instanceof CloudFoundryRunTarget) {
|
||||
return (CloudFoundryRunTarget) target;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
BootDashActivator.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create debugging target similar to a remote debugging session would and add them to the launch.
|
||||
* This is to support debugging of the remote boot-app that is reachable over http tunnel
|
||||
* the client creates. From our side this just as if we are opening a remote debug
|
||||
* session to the client.
|
||||
*/
|
||||
private void launchRemote(final SshTunnel tunnel, ILaunchConfiguration configuration, final ILaunch launch, IProgressMonitor _monitor) throws CoreException {
|
||||
int port = tunnel.getLocalPort();
|
||||
final IProgressMonitor monitor = _monitor==null?new NullProgressMonitor():_monitor;
|
||||
|
||||
monitor.beginTask(NLS.bind(LaunchingMessages.JavaRemoteApplicationLaunchConfigurationDelegate_Attaching_to__0_____1, new String[]{configuration.getName()}), 3);
|
||||
// check for cancellation
|
||||
if (monitor.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
monitor.subTask(LaunchingMessages.JavaRemoteApplicationLaunchConfigurationDelegate_Verifying_launch_attributes____1);
|
||||
|
||||
//String connectorId = "org.eclipse.jdt.launching.socketListenConnector";//getVMConnectorId(configuration);
|
||||
String connectorId = "org.eclipse.jdt.launching.socketAttachConnector";
|
||||
final IVMConnector connector = JavaRuntime.getVMConnector(connectorId);
|
||||
if (connector == null) {
|
||||
abort(LaunchingMessages.JavaRemoteApplicationLaunchConfigurationDelegate_Connector_not_specified_2, null, IJavaLaunchConfigurationConstants.ERR_CONNECTOR_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
final Map<String, String> argMap = new HashMap<>();
|
||||
|
||||
int connectTimeout = Platform.getPreferencesService().getInt(
|
||||
LaunchingPlugin.ID_PLUGIN,
|
||||
JavaRuntime.PREF_CONNECT_TIMEOUT,
|
||||
JavaRuntime.DEF_CONNECT_TIMEOUT,
|
||||
null);
|
||||
argMap.put("hostname", "localhost");
|
||||
argMap.put("timeout", ""+connectTimeout);
|
||||
argMap.put("port", ""+port);
|
||||
|
||||
// check for cancellation
|
||||
if (monitor.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor.worked(1);
|
||||
|
||||
|
||||
monitor.subTask(LaunchingMessages.JavaRemoteApplicationLaunchConfigurationDelegate_Creating_source_locator____2);
|
||||
// set the default source locator if required
|
||||
setDefaultSourceLocator(launch, configuration);
|
||||
monitor.worked(1);
|
||||
|
||||
// connect to remote VM
|
||||
try {
|
||||
new WaitFor(DEBUG_CONNECT_TIMEOUT) {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
connector.connect(argMap, monitor, launch);
|
||||
}
|
||||
};
|
||||
new ProcessTracker(new ProcessListenerAdapter() {
|
||||
@Override
|
||||
public void debugTargetTerminated(ProcessTracker tracker, IDebugTarget target) {
|
||||
handleTermination(tracker, target.getLaunch());
|
||||
}
|
||||
@Override
|
||||
public void processTerminated(ProcessTracker tracker, IProcess process) {
|
||||
handleTermination(tracker, process.getLaunch());
|
||||
}
|
||||
private void handleTermination(ProcessTracker tracker, ILaunch targetLaunch) {
|
||||
if (launch.equals(targetLaunch)) {
|
||||
tracker.dispose();
|
||||
tunnel.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
terminateAllTargets(launch);
|
||||
throw ExceptionUtil.coreException(e);
|
||||
}
|
||||
|
||||
// check for cancellation
|
||||
if (monitor.isCanceled()) {
|
||||
terminateAllTargets(launch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
monitor.done();
|
||||
}
|
||||
}
|
||||
|
||||
public void terminateAllTargets(final ILaunch launch) {
|
||||
//Note: its better to discconect debugtargets before terminating processes
|
||||
// because that allows a cleaner disconnect from the debugged process.
|
||||
// (If the devtools client process is terminated its no longer possible to talk to the
|
||||
// debugged process).
|
||||
IDebugTarget[] debugTargets = launch.getDebugTargets();
|
||||
for (int i = 0; i < debugTargets.length; i++) {
|
||||
IDebugTarget target = debugTargets[i];
|
||||
if (target.canDisconnect()) {
|
||||
try {
|
||||
target.disconnect();
|
||||
} catch (Exception e) {
|
||||
BootActivator.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
IProcess[] processes = launch.getProcesses();
|
||||
for (IProcess process : processes) {
|
||||
if (process.canTerminate()) {
|
||||
try {
|
||||
process.terminate();
|
||||
} catch (Exception e) {
|
||||
BootActivator.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ILaunchConfiguration getOrCreateLaunchConfig(CloudAppDashElement app) throws CoreException {
|
||||
IProject project = app.getProject();
|
||||
String appName = app.getName();
|
||||
CloudFoundryRunTarget target = app.getTarget();
|
||||
Assert.isTrue(project!=null);
|
||||
ILaunchConfiguration existing = findConfig(project, target, appName);
|
||||
ILaunchConfigurationWorkingCopy wc;
|
||||
if (existing!=null) {
|
||||
return existing;
|
||||
} else {
|
||||
wc = createConfiguration(project, target, appName);
|
||||
return wc.doSave();
|
||||
}
|
||||
}
|
||||
|
||||
private static ILaunchConfigurationWorkingCopy createConfiguration(IProject project, CloudFoundryRunTarget target, String appName) throws CoreException {
|
||||
ILaunchConfigurationType configType = getLaunchType();
|
||||
ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, getLaunchMan().generateLaunchConfigurationName("ssh-tunnel["+appName+"]"));
|
||||
BootLaunchConfigurationDelegate.setProject(wc, project);
|
||||
setRunTarget(wc, target);
|
||||
setAppName(wc, appName);
|
||||
wc.setMappedResources(new IResource[] {project});
|
||||
return wc;
|
||||
}
|
||||
|
||||
public static ILaunchConfiguration findConfig(CloudAppDashElement app) {
|
||||
IProject project = app.getProject();
|
||||
String appName = app.getName();
|
||||
CloudFoundryRunTarget target = app.getTarget();
|
||||
return findConfig(project, target, appName);
|
||||
}
|
||||
|
||||
private static ILaunchConfiguration findConfig(IProject project, CloudFoundryRunTarget target, String appName) {
|
||||
try {
|
||||
if (project!=null) {
|
||||
for (ILaunchConfiguration c : getLaunchMan().getLaunchConfigurations(getLaunchType())) {
|
||||
if (
|
||||
project.equals(BootLaunchConfigurationDelegate.getProject(c)) &&
|
||||
target.getId().equals(getRunTargetId(c)) &&
|
||||
appName.equals(getAppName(c))
|
||||
) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
BootActivator.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ILaunchConfigurationType getLaunchType() {
|
||||
return getLaunchMan().getLaunchConfigurationType(TYPE_ID);
|
||||
}
|
||||
|
||||
|
||||
public static void doLaunch(CloudAppDashElement app, IProgressMonitor monitor) throws CoreException {
|
||||
ILaunchConfiguration conf = SshDebugLaunchConfigurationDelegate.getOrCreateLaunchConfig(app);
|
||||
conf.launch(ILaunchManager.DEBUG_MODE, monitor);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
|
||||
import org.eclipse.debug.ui.CommonTab;
|
||||
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
|
||||
import org.eclipse.debug.ui.ILaunchConfigurationTab;
|
||||
import org.eclipse.debug.ui.ILaunchConfigurationTabGroup;
|
||||
import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
|
||||
|
||||
public class SshDebugLaunchConfigurationTabGroup extends AbstractLaunchConfigurationTabGroup {
|
||||
|
||||
/**
|
||||
* @see ILaunchConfigurationTabGroup#createTabs(ILaunchConfigurationDialog, String)
|
||||
*/
|
||||
@Override
|
||||
public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
|
||||
ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] {
|
||||
new SshDebugMainTab(),
|
||||
//new JavaArgumentsTab(),
|
||||
//new JavaJRETab(),
|
||||
//new JavaClasspathTab(),
|
||||
new SourceLookupTab(),
|
||||
//new EnvironmentTab(),
|
||||
new CommonTab()
|
||||
};
|
||||
setTabs(tabs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
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.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springframework.ide.eclipse.boot.launch.ExistingBootProjectSelectionValidator;
|
||||
import org.springframework.ide.eclipse.boot.launch.SelectProjectLaunchTabModel;
|
||||
import org.springframework.ide.eclipse.boot.launch.devtools.DevtoolsEnabledValidator;
|
||||
import org.springframework.ide.eclipse.boot.launch.devtools.StringFieldLaunchTabModel;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.CompositeValidator;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.StringFieldModel;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.Validator;
|
||||
|
||||
/**
|
||||
* Model for the 'main type' selection widgetry on a launchconfiguration tab.
|
||||
* <p>
|
||||
* Contains the 'logic' for the UI except for the widgets themselves.
|
||||
* Can be unit tested without having to instantiate launch configuration dialogs
|
||||
* etc.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SshDebugLaunchUIModel {
|
||||
|
||||
public final SelectProjectLaunchTabModel project;
|
||||
public final SelectRunTargetLaunchTabModel cfTarget;
|
||||
public final StringFieldLaunchTabModel appName;
|
||||
private BootDashViewModel context;
|
||||
|
||||
public SshDebugLaunchUIModel(BootDashViewModel context) {
|
||||
this.context = context;
|
||||
project = createProjectSelectionModel();
|
||||
cfTarget = createCfTargetModel(context);
|
||||
appName = createAppNameModel();
|
||||
}
|
||||
|
||||
private SelectRunTargetLaunchTabModel createCfTargetModel(BootDashViewModel context) {
|
||||
LiveVariable<CloudFoundryRunTarget> variable = new LiveVariable<>();
|
||||
LiveExpression<ValidationResult> validator = Validator.notNull(variable, "No Target selected");
|
||||
return new SelectRunTargetLaunchTabModel(variable, validator, context);
|
||||
}
|
||||
|
||||
private StringFieldLaunchTabModel createAppNameModel() {
|
||||
StringFieldModel field = new StringFieldModel("App Name", "");
|
||||
field.validator(appNameValidator(project.selection, cfTarget.selection, field.getVariable()));
|
||||
return new StringFieldLaunchTabModel(field, SshDebugLaunchConfigurationDelegate.APP_NAME);
|
||||
}
|
||||
|
||||
|
||||
private LiveExpression<ValidationResult> appNameValidator(
|
||||
final LiveExpression<IProject> projectSelection,
|
||||
final LiveExpression<CloudFoundryRunTarget> targetSelection,
|
||||
final LiveExpression<String> appNameSelection
|
||||
) {
|
||||
return new Validator() {
|
||||
{
|
||||
dependsOn(projectSelection);
|
||||
dependsOn(appNameSelection);
|
||||
dependsOn(targetSelection);
|
||||
}
|
||||
protected ValidationResult compute() {
|
||||
CloudFoundryRunTarget target = targetSelection.getValue();
|
||||
if (target!=null) {
|
||||
String name = appNameSelection.getValue();
|
||||
if (!StringUtil.hasText(name)) {
|
||||
return ValidationResult.error("App Name not set");
|
||||
}
|
||||
BootDashModel section = context.getSectionByTargetId(target.getId());
|
||||
if (section instanceof CloudFoundryBootDashModel) {
|
||||
CloudFoundryBootDashModel cfSection = (CloudFoundryBootDashModel) section;
|
||||
CloudAppDashElement app = cfSection.getApplication(name);
|
||||
if (app==null) {
|
||||
return ValidationResult.error("There is no app '"+name+"' in '"+target+"'");
|
||||
}
|
||||
IProject project = projectSelection.getValue();
|
||||
IProject appProject = app.getProject();
|
||||
if (appProject==null) {
|
||||
// we don't know what project goes with selected app so give the user
|
||||
// the benefit of the doubdt
|
||||
// => no error!
|
||||
} else if (project==null) {
|
||||
// not this validator's problem. (project validator should check this)
|
||||
// => no error
|
||||
} else {
|
||||
if (!project.equals(appProject)) {
|
||||
return ValidationResult.error("The app '"+name+"' is bound to a different project ("+appProject.getName()+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private SelectProjectLaunchTabModel createProjectSelectionModel() {
|
||||
LiveVariable<IProject> project = new LiveVariable<>();
|
||||
CompositeValidator validator = new CompositeValidator();
|
||||
validator.addChild(new ExistingBootProjectSelectionValidator(project));
|
||||
validator.addChild(new DevtoolsEnabledValidator(project));
|
||||
return new SelectProjectLaunchTabModel(project, validator);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import static org.springframework.ide.eclipse.boot.ui.BootUIImages.BOOT_DEVTOOLS_ICON;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.launch.SelectProjectLaunchTabSection;
|
||||
import org.springframework.ide.eclipse.boot.launch.devtools.StringFieldLaunchTabSection;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.LaunchConfigurationTabWithSections;
|
||||
import org.springframework.ide.eclipse.boot.ui.BootUIImages;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.IPageSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.IPageWithSections;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SshDebugMainTab extends LaunchConfigurationTabWithSections implements IPageWithSections {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "SSH Tunnel";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getImage() {
|
||||
return BootUIImages.getImage(BOOT_DEVTOOLS_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IPageSection> createSections() {
|
||||
SshDebugLaunchUIModel model = new SshDebugLaunchUIModel(BootDashActivator.getDefault().getModel());
|
||||
return Arrays.asList(new IPageSection[] {
|
||||
SelectProjectLaunchTabSection.create(this, model.project),
|
||||
SelectRunTargetLaunchTabSection.create(this, model.cfTarget),
|
||||
StringFieldLaunchTabSection.create(this, model.appName)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.debug;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.model.CloudAppDashElement;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.ops.CloudApplicationOperation;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SshDebugStartOperation extends CloudApplicationOperation {
|
||||
|
||||
private CloudAppDashElement app;
|
||||
|
||||
public SshDebugStartOperation(CloudAppDashElement app, DebugSupport debugSupport, CancelationToken cancelationToken) {
|
||||
super("Starting SSH debugging for app '"+app.getName()+"'", app.getBootDashModel(), app.getName(), cancelationToken);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doCloudOp(IProgressMonitor monitor) throws Exception, OperationCanceledException {
|
||||
//TODO: wireup a progress monitor to pass to 'doLaunch' so its aware of cancelation token
|
||||
SshDebugLaunchConfigurationDelegate.doLaunch(app, monitor);
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import static org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugLaunchConfigurationDelegate.getApp;
|
||||
import static org.springframework.ide.eclipse.boot.dash.cf.debug.SshDebugLaunchConfigurationDelegate.getLaunchType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.debug.core.ILaunch;
|
||||
import org.eclipse.debug.core.ILaunchConfiguration;
|
||||
import org.eclipse.debug.core.ILaunchConfigurationType;
|
||||
import org.eclipse.debug.core.model.IDebugTarget;
|
||||
import org.springframework.ide.eclipse.boot.core.BootActivator;
|
||||
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.ops.Operation;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens.CancelationToken;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.BootLaunchUtils;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
|
||||
/**
|
||||
* Uses ssh tunnelling on Diego to support debugging of app running on CF.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SshDebugSupport extends DebugSupport {
|
||||
|
||||
public static final SshDebugSupport INSTANCE = new SshDebugSupport();
|
||||
|
||||
private static final int REMOTE_DEBUG_PORT = 47822;
|
||||
private static final String REMOTE_DEBUG_JVM_ARGS = "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n,address="+REMOTE_DEBUG_PORT;
|
||||
private static final String JAVA_OPTS = "JAVA_OPTS";
|
||||
|
||||
private SshDebugSupport() {}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(CloudAppDashElement app) {
|
||||
String notSupportedMessage = getNotSupportedMessage(app);
|
||||
return notSupportedMessage==null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotSupportedMessage(CloudAppDashElement app) {
|
||||
//TODO: There are a number of different ways that ssh and/or diego might be disabled for
|
||||
// an app. e.g. it can be disabled on the app itself, on the space, on the org or
|
||||
// on the whole CF installation. This check should recognize these situation.
|
||||
// At the moment it pretty much returns true if the CF has global info about the 'ssh-host',
|
||||
// but this probably usually the case on any recent enough version of PCF, even if
|
||||
// ssh has been explicitly disabled.
|
||||
CloudFoundryRunTarget target = app.getTarget();
|
||||
try {
|
||||
if (target.getSshClientSupport().getSshHost()==null) {
|
||||
return "Cloud controller doesn't specify an ssh-host. This probably means your version of CloudFoundry doesn't support SSH.";
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
BootDashActivator.log(e); //for traceability
|
||||
String msg = ExceptionUtil.getMessage(e);
|
||||
if (!StringUtil.hasText(msg)) {
|
||||
msg = "Exception: "+e.getClass().getName();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebuggerAttached(CloudAppDashElement app) {
|
||||
ILaunchConfiguration conf = SshDebugLaunchConfigurationDelegate.findConfig(app);
|
||||
if (conf!=null) {
|
||||
for (ILaunch l : BootLaunchUtils.getLaunches(conf)) {
|
||||
if (!l.isTerminated()) {
|
||||
for (IDebugTarget dt : l.getDebugTargets()) {
|
||||
if (!dt.isTerminated()) {
|
||||
//Active debug target found, so debugger is attached.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation<?> createOperation(CloudAppDashElement app, String opName, UserInteractions ui, CancelationToken cancelationToken) {
|
||||
return new SshDebugStartOperation(app, this, cancelationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEnvVars(Map<String, String> env) {
|
||||
String javaOpts = clearJavaOpts(env.get(JAVA_OPTS));
|
||||
StringBuilder sb = new StringBuilder(javaOpts);
|
||||
if (sb.length() > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(REMOTE_DEBUG_JVM_ARGS);
|
||||
env.put(JAVA_OPTS, sb.toString());
|
||||
|
||||
}
|
||||
|
||||
private static String clearJavaOpts(String opts) {
|
||||
if (opts!=null) {
|
||||
opts = opts.replaceAll(REMOTE_DEBUG_JVM_ARGS + "\\s*", "");
|
||||
return opts;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearEnvVars(Map<String, String> env) {
|
||||
String jopts = clearJavaOpts(env.get(JAVA_OPTS));
|
||||
if (StringUtil.hasText(jopts)) {
|
||||
env.put(JAVA_OPTS, clearJavaOpts(env.get(JAVA_OPTS)));
|
||||
} else {
|
||||
env.remove(JAVA_OPTS);
|
||||
}
|
||||
}
|
||||
|
||||
public int getRemotePort() {
|
||||
return REMOTE_DEBUG_PORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudAppDashElement getElementFor(ILaunch l, BootDashViewModel context) {
|
||||
try {
|
||||
ILaunchConfigurationType interestingType = getLaunchType();
|
||||
ILaunchConfiguration conf = l.getLaunchConfiguration();
|
||||
if (interestingType.equals(conf.getType())) {
|
||||
return getApp(conf, context);
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
BootActivator.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.debug;
|
||||
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.OnDispose;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
|
||||
|
||||
public interface SshTunnel extends Disposable, OnDispose {
|
||||
|
||||
int getLocalPort();
|
||||
|
||||
boolean isDisposed();
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.SshHost;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.LogSink;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SshTunnelFactory {
|
||||
|
||||
SshTunnel create(
|
||||
SshHost sshHost,
|
||||
String user,
|
||||
String oneTimeCode,
|
||||
int remotePort,
|
||||
LogSink log,
|
||||
int localPort
|
||||
) throws Exception;
|
||||
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
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.cf.client.SshHost;
|
||||
import org.springframework.ide.eclipse.boot.dash.util.LogSink;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.AbstractDisposable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
|
||||
import net.schmizz.keepalive.KeepAliveProvider;
|
||||
import net.schmizz.keepalive.KeepAliveRunner;
|
||||
import net.schmizz.sshj.DefaultConfig;
|
||||
import net.schmizz.sshj.SSHClient;
|
||||
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
|
||||
|
||||
/**
|
||||
* This class is responsible for creating an ssh tunnel to a remote port. This class implements
|
||||
* Closeable, its close method must be called to close the tunnel and avoid resource leak.
|
||||
*/
|
||||
public class SshTunnelImpl extends AbstractDisposable implements SshTunnel {
|
||||
|
||||
private boolean closeRequested = false;
|
||||
private int localPort;
|
||||
private SSHClient ssh;
|
||||
private LocalPortForwarder portForwarder;
|
||||
|
||||
public SshTunnelImpl(SshHost sshHost, String user, String oneTimeCode, int remotePort, LogSink log) throws Exception {
|
||||
this(sshHost, user, oneTimeCode, remotePort, log, 0);
|
||||
}
|
||||
|
||||
public SshTunnelImpl(SshHost sshHost, String user, String oneTimeCode, int remotePort, LogSink log, int _localPort) throws Exception {
|
||||
DefaultConfig config = new DefaultConfig();
|
||||
config.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE); // Hopefuly this is better at detecting dropped connections from server (e.g. when app is stopped or dies).
|
||||
ssh = new SSHClient(config);
|
||||
ssh.addHostKeyVerifier(sshHost.getFingerPrint());
|
||||
log.log("Ssh client created");
|
||||
|
||||
ssh.connect(sshHost.getHost(), sshHost.getPort());
|
||||
ssh.authPassword(user, oneTimeCode);
|
||||
KeepAliveRunner keepAlive = (KeepAliveRunner) ssh.getConnection().getKeepAlive();
|
||||
keepAlive.setKeepAliveInterval(5);
|
||||
keepAlive.setMaxAliveCount(1);
|
||||
log.log("Ssh client connected");
|
||||
|
||||
ServerSocket ss = new ServerSocket(_localPort);
|
||||
ss.setSoTimeout(5_000);
|
||||
localPort = ss.getLocalPort();
|
||||
Job job = new Job("SshTunnel port forwarding") {
|
||||
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor arg0) {
|
||||
final LocalPortForwarder.Parameters params = new LocalPortForwarder.Parameters("0.0.0.0", localPort, "localhost", remotePort);
|
||||
try {
|
||||
portForwarder = ssh.newLocalPortForwarder(params, ss);
|
||||
boolean retry;
|
||||
do {
|
||||
retry = false;
|
||||
try {
|
||||
portForwarder.listen();
|
||||
} catch (IOException e) {
|
||||
if (!closeRequested) {
|
||||
if (e instanceof SocketTimeoutException) {
|
||||
//don't log it happens all the time and is expected
|
||||
} else {
|
||||
log.log(ExceptionUtil.getMessage(e));
|
||||
}
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
} while (retry);
|
||||
} finally {
|
||||
try {
|
||||
ss.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
job.setSystem(true);
|
||||
job.schedule();
|
||||
log.log("Ssh tunnel created: localPort = "+localPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized public void dispose() {
|
||||
if (portForwarder!=null) {
|
||||
try {
|
||||
portForwarder.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
portForwarder = null;
|
||||
}
|
||||
if (ssh!=null) {
|
||||
try {
|
||||
ssh.disconnect();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
ssh = null;
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
return localPort;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.IAnnotationPresentation;
|
||||
import org.eclipse.jface.text.source.ImageUtilities;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.FontMetrics;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
|
||||
/**
|
||||
* Annotation for application name. Can be selected and unselected. Based on JDT
|
||||
* projection annotation
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameAnnotation extends Annotation implements IAnnotationPresentation {
|
||||
/**
|
||||
* The type of CF application name annotations.
|
||||
*/
|
||||
public static final String TYPE = "cf.app.name"; //$NON-NLS-1$
|
||||
|
||||
private static final int COLOR= SWT.COLOR_GRAY;
|
||||
|
||||
/** The state of this annotation */
|
||||
private boolean fIsSelected= false;
|
||||
/** Indicates whether this annotation should be painted as range */
|
||||
private boolean fIsRangeIndication= false;
|
||||
|
||||
/**
|
||||
* Creates a new annotation. When <code>isSelected</code>
|
||||
* is <code>true</code> the annotation is initially selected.
|
||||
*
|
||||
* @param isSelected <code>true</code> if the annotation should initially be selected, <code>false</code> otherwise
|
||||
*/
|
||||
public AppNameAnnotation(String text) {
|
||||
super(TYPE, false, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new annotation.
|
||||
*
|
||||
* @param text the app name
|
||||
* @param selected selected or unselected
|
||||
*/
|
||||
public AppNameAnnotation(String text, boolean selected) {
|
||||
this(text);
|
||||
fIsSelected = selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables and disables the range indication for this annotation.
|
||||
*
|
||||
* @param rangeIndication the enable state for the range indication
|
||||
*/
|
||||
public void setRangeIndication(boolean rangeIndication) {
|
||||
fIsRangeIndication= rangeIndication;
|
||||
}
|
||||
|
||||
private void drawRangeIndication(GC gc, Canvas canvas, Rectangle r) {
|
||||
final int MARGIN= 3;
|
||||
|
||||
/* cap the height - at least on GTK, large numbers are converted to
|
||||
* negatives at some point */
|
||||
int height= Math.min(r.y + r.height - MARGIN, canvas.getSize().y);
|
||||
|
||||
gc.setForeground(canvas.getDisplay().getSystemColor(COLOR));
|
||||
gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance
|
||||
gc.drawLine(r.x + 4, r.y + 12, r.x + 4, height);
|
||||
gc.drawLine(r.x + 4, height, r.x + r.width - MARGIN, height);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IAnnotationPresentation#paint(org.eclipse.swt.graphics.GC, org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
|
||||
*/
|
||||
public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
|
||||
Image image= getImage();
|
||||
if (image != null) {
|
||||
ImageUtilities.drawImage(image, gc, canvas, rectangle, SWT.CENTER, SWT.TOP);
|
||||
if (fIsRangeIndication) {
|
||||
FontMetrics fontMetrics= gc.getFontMetrics();
|
||||
int delta= (fontMetrics.getHeight() - image.getBounds().height)/2;
|
||||
rectangle.y += delta;
|
||||
rectangle.height -= delta;
|
||||
drawRangeIndication(gc, canvas, rectangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
|
||||
*/
|
||||
public int getLayer() {
|
||||
return IAnnotationPresentation.DEFAULT_LAYER;
|
||||
}
|
||||
|
||||
private Image getImage() {
|
||||
return isSelected() ? BootDashActivator.getDefault().getImageRegistry().get(BootDashActivator.CHECK_ICON)
|
||||
: BootDashActivator.getDefault().getImageRegistry().get(BootDashActivator.CHECK_GREYSCALE_ICON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of this annotation.
|
||||
*
|
||||
* @return <code>true</code> if collapsed
|
||||
*/
|
||||
public boolean isSelected() {
|
||||
return fIsSelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this annotation as being selected.
|
||||
*/
|
||||
public void markSelected() {
|
||||
fIsSelected= true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this annotation as being unselected.
|
||||
*/
|
||||
public void markUnselected() {
|
||||
fIsSelected= false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.deployment;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationModel;
|
||||
|
||||
/**
|
||||
* Application Name annotations model
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameAnnotationModel extends AnnotationModel {
|
||||
|
||||
/**
|
||||
* Annotation model key for attachment to viewer visual annotations model
|
||||
*/
|
||||
public static final Object APP_NAME_MODEL_KEY = new Object();
|
||||
|
||||
/**
|
||||
* Constant application name. If not <code>null</code> then corresponding annotation must be selected
|
||||
*/
|
||||
public final String fixedAppName;
|
||||
|
||||
/**
|
||||
* Creates a new, empty projection annotation model.
|
||||
*/
|
||||
public AppNameAnnotationModel(String fixedAppName) {
|
||||
this.fixedAppName = fixedAppName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given annotation as selected. An appropriate
|
||||
* annotation model change event is sent out.
|
||||
*
|
||||
* @param annotation the annotation
|
||||
*/
|
||||
public void markSelected(Annotation annotation) {
|
||||
if (annotation instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation appName = (AppNameAnnotation) annotation;
|
||||
Iterator<?> iterator= getAnnotationIterator();
|
||||
while(iterator.hasNext()) {
|
||||
Object o = iterator.next();
|
||||
if (o instanceof AppNameAnnotation && appName != o) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) o;
|
||||
if (a.isSelected()) {
|
||||
a.markUnselected();
|
||||
modifyAnnotation(a, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!appName.isSelected()) {
|
||||
appName.markSelected();
|
||||
modifyAnnotation(appName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first selected annotation
|
||||
*
|
||||
* @return the selected annotation
|
||||
*/
|
||||
public AppNameAnnotation getSelectedAppAnnotation() {
|
||||
Iterator<?> iterator= getAnnotationIterator();
|
||||
while(iterator.hasNext()) {
|
||||
Object o = iterator.next();
|
||||
if (o instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) o;
|
||||
if (a.isSelected()) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds application name annotation corresponding to the passed in
|
||||
* application name text parameter
|
||||
*
|
||||
* @param text Application name text
|
||||
* @return annotation corresponding to the application name text
|
||||
*/
|
||||
public AppNameAnnotation getAnnotation(String text) {
|
||||
if (text != null) {
|
||||
Iterator<?> iterator= getAnnotationIterator();
|
||||
while(iterator.hasNext()) {
|
||||
Object o = iterator.next();
|
||||
if (o instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) o;
|
||||
if (text.equals(a.getText())) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.deployment;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextInputListener;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationPainter;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccess;
|
||||
import org.eclipse.jface.text.source.IAnnotationHover;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.ISharedTextColors;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.ISourceViewerExtension2;
|
||||
import org.eclipse.jface.text.source.SourceViewer;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.custom.StyledTextContent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.Log;
|
||||
|
||||
/**
|
||||
* Application name annotation support for the {@link ISourceViewer}
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameAnnotationSupport {
|
||||
|
||||
/**
|
||||
* Unselected application name annotation line color
|
||||
*/
|
||||
private static final RGB APP_NAME_COLOR = new RGB(0xBB, 0xBB, 0xBB);
|
||||
|
||||
/**
|
||||
* Selected application name annotation line color
|
||||
*/
|
||||
private static final RGB SELECTED_APP_NAME_COLOR = new RGB(0x00, 0x87, 0x00);
|
||||
|
||||
/**
|
||||
* Alpha value for painting application name annotations line highlighting
|
||||
* (Must be close to 0 to ensure the text behind is visible enough)
|
||||
*/
|
||||
private static final int APP_NAME_ANNOTATION_ALPHA = 0x17;
|
||||
|
||||
/**
|
||||
* Width of the application name annotations vertical ruler control
|
||||
*/
|
||||
private static final int ANNOTATION_COLUMN_WIDTH = 12;
|
||||
|
||||
/**
|
||||
* The source viewer
|
||||
*/
|
||||
private SourceViewer fViewer = null;
|
||||
|
||||
/**
|
||||
* Application name annotations vertical ruler
|
||||
*/
|
||||
private AppNameRulerColumn fColumn = null;
|
||||
|
||||
/**
|
||||
* Constant colors cache (passed in)
|
||||
*/
|
||||
private ISharedTextColors fColorsCache;
|
||||
|
||||
private final String fixedAppName;
|
||||
|
||||
/**
|
||||
* Listen to viewer input changes to attach the application name annotations model if necessary
|
||||
*/
|
||||
private ITextInputListener textInputListener = new ITextInputListener() {
|
||||
|
||||
public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
|
||||
initAppAnnotationModel();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private void initAppAnnotationModel() {
|
||||
IAnnotationModel annotationModel = fViewer.getVisualAnnotationModel();
|
||||
if (annotationModel instanceof IAnnotationModelExtension) {
|
||||
IAnnotationModelExtension extension = (IAnnotationModelExtension) annotationModel;
|
||||
if (extension.getAnnotationModel(AppNameAnnotationModel.APP_NAME_MODEL_KEY) == null) {
|
||||
extension.addAnnotationModel(AppNameAnnotationModel.APP_NAME_MODEL_KEY, new AppNameAnnotationModel(fixedAppName));
|
||||
}
|
||||
}
|
||||
fColumn.setModel(annotationModel);
|
||||
}
|
||||
|
||||
public AppNameAnnotationSupport(SourceViewer viewer, IAnnotationAccess annotationAccess, ISharedTextColors colorsCache, String fixedAppName) {
|
||||
super();
|
||||
this.fixedAppName = fixedAppName;
|
||||
fViewer = viewer;
|
||||
fViewer.addTextInputListener(textInputListener);
|
||||
|
||||
fColorsCache = colorsCache;
|
||||
fColumn = new AppNameRulerColumn(ANNOTATION_COLUMN_WIDTH, annotationAccess);
|
||||
fColumn.addAnnotationType(AppNameAnnotation.TYPE);
|
||||
|
||||
/*
|
||||
* Setup tooltip for application name annotations
|
||||
*/
|
||||
fColumn.setHover(new IAnnotationHover() {
|
||||
@Override
|
||||
public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
|
||||
for (Iterator<?> itr = fColumn.getModel().getAnnotationIterator(); itr.hasNext();) {
|
||||
Object o = itr.next();
|
||||
if (o instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) o;
|
||||
Position p = fColumn.getModel().getPosition(a);
|
||||
try {
|
||||
if (fViewer.getDocument().getLineOfOffset(p.getOffset()) <= lineNumber && fViewer.getDocument().getLineOfOffset(p.getOffset() + p.getLength() - 1) >= lineNumber) {
|
||||
String hoverText = "Application '" + a.getText() + "'";
|
||||
if (a.isSelected()) {
|
||||
hoverText += " is selected";
|
||||
}
|
||||
return hoverText;
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
* Setup application name line highlight painting on the viewer's text widget
|
||||
*/
|
||||
AppNameAnnotationsPainter annotationPainter= new AppNameAnnotationsPainter(fViewer, annotationAccess);
|
||||
annotationPainter.addDrawingStrategy(AppNameAnnotationModel.APP_NAME_MODEL_KEY, new AppNameDrawingStrategy());
|
||||
annotationPainter.addAnnotationType(AppNameAnnotation.TYPE, AppNameAnnotationModel.APP_NAME_MODEL_KEY);
|
||||
annotationPainter.setAnnotationTypeColor(AppNameAnnotation.TYPE, fViewer.getControl().getDisplay().getSystemColor(SWT.COLOR_GRAY));
|
||||
initAppAnnotationModel();
|
||||
fViewer.addPainter(annotationPainter);
|
||||
|
||||
/*
|
||||
* Attach application annotations ruler to the viewer
|
||||
*/
|
||||
if (fixedAppName == null) {
|
||||
fViewer.addVerticalRulerColumn(fColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
fViewer.removeTextInputListener(textInputListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns viewer's application name annotations model
|
||||
*
|
||||
* @param viewer Source viewer
|
||||
* @return Viewer's application name annotations model
|
||||
*/
|
||||
public static AppNameAnnotationModel getAppNameAnnotationModel(ISourceViewer viewer) {
|
||||
IAnnotationModel model = viewer instanceof ISourceViewerExtension2
|
||||
? ((ISourceViewerExtension2) viewer).getVisualAnnotationModel() : viewer.getAnnotationModel();
|
||||
AppNameAnnotationModel appNameModel = null;
|
||||
if (model instanceof IAnnotationModelExtension) {
|
||||
appNameModel = (AppNameAnnotationModel) ((IAnnotationModelExtension) model)
|
||||
.getAnnotationModel(AppNameAnnotationModel.APP_NAME_MODEL_KEY);
|
||||
} else if (model instanceof AppNameAnnotationModel) {
|
||||
appNameModel = (AppNameAnnotationModel) model;
|
||||
}
|
||||
return appNameModel;
|
||||
}
|
||||
|
||||
private static class AppNameAnnotationsPainter extends AnnotationPainter {
|
||||
|
||||
/**
|
||||
* Creates a new painter indicating the location of collapsed regions.
|
||||
*
|
||||
* @param sourceViewer the source viewer for the painter
|
||||
* @param access the annotation access
|
||||
*/
|
||||
public AppNameAnnotationsPainter(ISourceViewer sourceViewer, IAnnotationAccess access) {
|
||||
super(sourceViewer, access);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.AnnotationPainter#findAnnotationModel(org.eclipse.jface.text.source.ISourceViewer)
|
||||
*/
|
||||
protected IAnnotationModel findAnnotationModel(ISourceViewer sourceViewer) {
|
||||
return getAppNameAnnotationModel(sourceViewer);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.AnnotationPainter#skip(org.eclipse.jface.text.source.Annotation)
|
||||
*/
|
||||
protected boolean skip(Annotation annotation) {
|
||||
return !(annotation instanceof AppNameAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
private class AppNameDrawingStrategy implements AnnotationPainter.IDrawingStrategy {
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy#draw(org.eclipse.swt.graphics.GC, org.eclipse.swt.custom.StyledText, int, int, org.eclipse.swt.graphics.Color)
|
||||
*/
|
||||
public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
|
||||
if (annotation instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) annotation;
|
||||
StyledTextContent content = textWidget.getContent();
|
||||
final int line = content.getLineAtOffset(offset);
|
||||
if (gc == null) {
|
||||
/*
|
||||
* Clear off highlighting case
|
||||
*/
|
||||
textWidget.setLineBackground(line, 1, null);
|
||||
textWidget.redrawRange(offset, length, true);
|
||||
} else {
|
||||
/*
|
||||
* Show highlighting case IMPORTANT: do not modify
|
||||
* 'textWidget' graphical parameters! It would start
|
||||
* scheduling async updates indefinitely! Hence other parts
|
||||
* of the UI won't have a chance to repaint themselves
|
||||
*/
|
||||
Position p = fColumn.getModel().getPosition(annotation);
|
||||
if (p != null && line == content.getLineAtOffset(p.getOffset())) {
|
||||
/*
|
||||
* Draw transparent line highlight rectangle. Ensure
|
||||
* it's transparent such that text behind it is visible
|
||||
*/
|
||||
Color lineColor = a.isSelected() ? fColorsCache.getColor(SELECTED_APP_NAME_COLOR)
|
||||
: fColorsCache.getColor(APP_NAME_COLOR);
|
||||
Color c = gc.getBackground();
|
||||
int opacity = gc.getAlpha();
|
||||
gc.setBackground(lineColor);
|
||||
gc.setAlpha(APP_NAME_ANNOTATION_ALPHA);
|
||||
gc.fillRectangle(0, textWidget.getLocationAtOffset(offset).y, textWidget.getClientArea().width,
|
||||
textWidget.getLineHeight());
|
||||
gc.setAlpha(opacity);
|
||||
gc.setBackground(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.deployment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.ast.YamlASTProvider;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.ast.YamlFileAST;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.Log;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||
import org.yaml.snakeyaml.nodes.SequenceNode;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
/**
|
||||
* Reconciler responsible for creating annotation at application names positions
|
||||
* in the Deployment YAML document
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameReconciler {
|
||||
|
||||
/**
|
||||
* YAML parser
|
||||
*/
|
||||
private YamlASTProvider fParser;
|
||||
|
||||
public AppNameReconciler(YamlASTProvider parser) {
|
||||
fParser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-populates annotation model with app name annotations based on document contents
|
||||
*
|
||||
* @param document The YAML document
|
||||
* @param annotationModel Application Names annotation model
|
||||
* @param monitor Progress monitor
|
||||
*/
|
||||
public void reconcile(IDocument document, AppNameAnnotationModel annotationModel, IProgressMonitor monitor) {
|
||||
if (annotationModel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Annotation> toRemove= new ArrayList<>();
|
||||
|
||||
Iterator<? extends Annotation> iter= annotationModel.getAnnotationIterator();
|
||||
while (iter.hasNext()) {
|
||||
Annotation annotation= iter.next();
|
||||
if (AppNameAnnotation.TYPE.equals(annotation.getType())) {
|
||||
toRemove.add(annotation);
|
||||
}
|
||||
}
|
||||
Annotation[] annotationsToRemove= toRemove.toArray(new Annotation[toRemove.size()]);
|
||||
|
||||
/*
|
||||
* Create brand new annotation to position map based on docs contents
|
||||
*/
|
||||
Map<AppNameAnnotation, Position> annotationsToAdd = createAnnotations(document, annotationModel, monitor);
|
||||
|
||||
/*
|
||||
* Update annotation model
|
||||
*/
|
||||
if (annotationModel instanceof IAnnotationModelExtension)
|
||||
((IAnnotationModelExtension)annotationModel).replaceAnnotations(annotationsToRemove, annotationsToAdd);
|
||||
else {
|
||||
for (int i= 0; i < annotationsToRemove.length; i++)
|
||||
annotationModel.removeAnnotation(annotationsToRemove[i]);
|
||||
for (iter= annotationsToAdd.keySet().iterator(); iter.hasNext();) {
|
||||
Annotation annotation= iter.next();
|
||||
annotationModel.addAnnotation(annotation, annotationsToAdd.get(annotation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new annotation to position mapping based on the document contents
|
||||
*
|
||||
* @param annotationModel Application name annotations model
|
||||
* @return Map of annotations to their corresponding positions
|
||||
*/
|
||||
private Map<AppNameAnnotation, Position> createAnnotations(IDocument document, AppNameAnnotationModel annotationModel, IProgressMonitor monitor) {
|
||||
Map<AppNameAnnotation, Position> annotationsMap = new LinkedHashMap<>();
|
||||
monitor.beginTask("Calculating application names", 100);
|
||||
try {
|
||||
YamlFileAST ast = fParser.getAST(document);
|
||||
String contents = document.get();
|
||||
List<Node> rootList = ast.getNodes();
|
||||
monitor.worked(70);
|
||||
if (rootList.size() == 1) {
|
||||
Node root = rootList.get(0);
|
||||
SequenceNode applicationsNode = YamlGraphDeploymentProperties.getNode(root, ApplicationManifestHandler.APPLICATIONS_PROP, SequenceNode.class);
|
||||
if (applicationsNode == null) {
|
||||
/*
|
||||
* No 'applications' YAML node consider root elements to the deployment properties of an application
|
||||
*/
|
||||
ScalarNode node = YamlGraphDeploymentProperties.getPropertyValue(root, ApplicationManifestHandler.NAME_PROP, ScalarNode.class);
|
||||
if (node != null) {
|
||||
/*
|
||||
* There is 'name' property present, so yes root has application deployment props
|
||||
*/
|
||||
annotationsMap.put(new AppNameAnnotation(node.getValue(), true),
|
||||
new Position(root.getStartMark().getIndex(),
|
||||
getLastWhiteCharIndex(contents, root.getEndMark().getIndex())
|
||||
- root.getStartMark().getIndex()));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Go through entries in the 'applications' sequence node
|
||||
*/
|
||||
for (Node appNode : applicationsNode.getValue()) {
|
||||
ScalarNode node = YamlGraphDeploymentProperties.getNode(appNode, ApplicationManifestHandler.NAME_PROP, ScalarNode.class);
|
||||
if (node != null) {
|
||||
/*
|
||||
* Add application name annotation entry
|
||||
*/
|
||||
annotationsMap.put(new AppNameAnnotation(node.getValue()), new Position(appNode.getStartMark().getIndex(), getLastWhiteCharIndex(contents, appNode.getEndMark().getIndex()) - appNode.getStartMark().getIndex()));
|
||||
}
|
||||
}
|
||||
}
|
||||
monitor.worked(20);
|
||||
if (!annotationsMap.isEmpty()) {
|
||||
if (annotationModel.fixedAppName == null) {
|
||||
/*
|
||||
* Select either previously selected app name annotation or the first found
|
||||
*/
|
||||
reselectAnnotation(annotationModel, annotationsMap);
|
||||
} else {
|
||||
/*
|
||||
* Select annotation corresponding to application name == to fAppName
|
||||
*/
|
||||
selectAnnotationByAppName(annotationsMap, annotationModel.fixedAppName);
|
||||
}
|
||||
monitor.worked(10);
|
||||
}
|
||||
}
|
||||
} catch (ParserException | ScannerException e) {
|
||||
// Ignore these exceptions as they'd appear as syntax errors in the editor
|
||||
} catch (Throwable t) {
|
||||
Log.log(t);
|
||||
} finally {
|
||||
monitor.done();
|
||||
}
|
||||
return annotationsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects annotation from the map corresponding to currently selected
|
||||
* annotation. Otherwise just selects the first found annotation
|
||||
*
|
||||
* @param annotationModel Application name annotations model
|
||||
* @param annotationsMap Map of application name annotations to positions
|
||||
*/
|
||||
private void reselectAnnotation(AppNameAnnotationModel annotationModel, Map<AppNameAnnotation, Position> annotationsMap) {
|
||||
AppNameAnnotation selected = annotationModel.getSelectedAppAnnotation();
|
||||
Map.Entry<AppNameAnnotation, Position> newSelected = null;
|
||||
if (selected != null) {
|
||||
Position selectedPosition = annotationModel.getPosition(selected);
|
||||
for (Map.Entry<AppNameAnnotation, Position> entry : annotationsMap.entrySet()) {
|
||||
/*
|
||||
* Check if application name matches
|
||||
*/
|
||||
if (entry.getKey().getText().equals(selected.getText())) {
|
||||
/*
|
||||
* If name matches see if previous match is further away
|
||||
* from previously selected annotation offset than the
|
||||
* current match. Update the match accordingly.
|
||||
*/
|
||||
if (newSelected == null) {
|
||||
newSelected = entry;
|
||||
} else if (Math.abs(newSelected.getValue().getOffset() - selectedPosition.getOffset()) > Math.abs(entry.getValue().getOffset() - selectedPosition.getOffset())){
|
||||
newSelected = entry;
|
||||
}
|
||||
} else if (entry.getValue().getOffset() == selectedPosition.getOffset() && newSelected == null) {
|
||||
newSelected = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newSelected == null) {
|
||||
/*
|
||||
* No matches found. Select the first annotation to have something selected.
|
||||
*/
|
||||
newSelected = annotationsMap.entrySet().iterator().next();
|
||||
}
|
||||
newSelected.getKey().markSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select annotation matching constant application name, i.e. <code>FAppName</code>
|
||||
*
|
||||
* @param annotationsMap Map of application name annotations to positions
|
||||
*/
|
||||
private void selectAnnotationByAppName(Map<AppNameAnnotation, Position> annotationsMap, String appName) {
|
||||
for (Map.Entry<AppNameAnnotation, Position> entry : annotationsMap.entrySet()) {
|
||||
if (entry.getKey().getText().equals(appName)) {
|
||||
entry.getKey().markSelected();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first 'white' char after a word appearing before the passed index
|
||||
*
|
||||
* @param text Text
|
||||
* @param index Index to start looking from
|
||||
* @return The first 'white' char position in a string
|
||||
*/
|
||||
private static int getLastWhiteCharIndex(String text, int index) {
|
||||
if (index == text.length()) {
|
||||
return index;
|
||||
}
|
||||
int i = index;
|
||||
for (; i >= 0 && Character.isWhitespace(text.charAt(i)); i--) {
|
||||
// Nothing to do
|
||||
}
|
||||
// Special case: if non white char is at position 'index' then return value of 'index'
|
||||
return i == index ? i : i + 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 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.deployment;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.text.reconciler.DirtyRegion;
|
||||
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
|
||||
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.ISourceViewerExtension2;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.ast.YamlASTProvider;
|
||||
|
||||
/**
|
||||
* Reconciling strategy responsible for keeping track of application name
|
||||
* annotations
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
|
||||
|
||||
/**
|
||||
* Reconciler for application name annotations
|
||||
*/
|
||||
private AppNameReconciler fReconciler;
|
||||
|
||||
/**
|
||||
* Source viewer
|
||||
*/
|
||||
private ISourceViewer fViewer;
|
||||
|
||||
/**
|
||||
* Document to perform reconciling on
|
||||
*/
|
||||
private IDocument fDocument;
|
||||
|
||||
/**
|
||||
* Reconciling cycle progress monitor
|
||||
*/
|
||||
private IProgressMonitor fProgressMonitor;
|
||||
|
||||
/**
|
||||
* Creates new instance of the reconciler
|
||||
*
|
||||
* @param viewer Source viewer
|
||||
* @param parser YAML parser
|
||||
* @param appName Application name to keep selected all the time
|
||||
*/
|
||||
public AppNameReconcilingStrategy(YamlASTProvider parser) {
|
||||
fReconciler = new AppNameReconciler(parser);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
|
||||
*/
|
||||
public void initialReconcile() {
|
||||
reconcile(new Region(0, fDocument.getLength()));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.reconciler.DirtyRegion,org.eclipse.jface.text.IRegion)
|
||||
*/
|
||||
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
|
||||
try {
|
||||
IRegion startLineInfo= fDocument.getLineInformationOfOffset(subRegion.getOffset());
|
||||
IRegion endLineInfo= fDocument.getLineInformationOfOffset(subRegion.getOffset() + Math.max(0, subRegion.getLength() - 1));
|
||||
if (startLineInfo.getOffset() == endLineInfo.getOffset())
|
||||
subRegion= startLineInfo;
|
||||
else
|
||||
subRegion= new Region(startLineInfo.getOffset(), endLineInfo.getOffset() + Math.max(0, endLineInfo.getLength() - 1) - startLineInfo.getOffset());
|
||||
|
||||
} catch (BadLocationException e) {
|
||||
subRegion= new Region(0, fDocument.getLength());
|
||||
}
|
||||
reconcile(subRegion);
|
||||
}
|
||||
|
||||
private AppNameAnnotationModel getAppNameAnnotationModel() {
|
||||
IAnnotationModel model = fViewer instanceof ISourceViewerExtension2 ? ((ISourceViewerExtension2)fViewer).getVisualAnnotationModel() : fViewer.getAnnotationModel();
|
||||
if (model instanceof IAnnotationModelExtension) {
|
||||
return (AppNameAnnotationModel) ((IAnnotationModelExtension) model).getAnnotationModel(AppNameAnnotationModel.APP_NAME_MODEL_KEY);
|
||||
}
|
||||
return (AppNameAnnotationModel) model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IRegion region) {
|
||||
fReconciler.reconcile(fDocument, getAppNameAnnotationModel(), fProgressMonitor);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public final void setProgressMonitor(IProgressMonitor monitor) {
|
||||
fProgressMonitor= monitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocument(IDocument document) {
|
||||
fDocument= document;
|
||||
}
|
||||
|
||||
public void install(ISourceViewer viewer) {
|
||||
fViewer = viewer;
|
||||
}
|
||||
|
||||
public void uninstall() {
|
||||
fViewer = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.AnnotationRulerColumn;
|
||||
import org.eclipse.jface.text.source.CompositeRuler;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccess;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseMoveListener;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
|
||||
/**
|
||||
* Application name annotations ruler control. Implementation based on
|
||||
* ProjectionRulerColumn class implementation
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class AppNameRulerColumn extends AnnotationRulerColumn {
|
||||
|
||||
/**
|
||||
* Currently examined/hovered over annotation
|
||||
*/
|
||||
private AppNameAnnotation fCurrentAnnotation;
|
||||
|
||||
/**
|
||||
* Line number recorded on mouse down.
|
||||
*/
|
||||
private int fMouseDownLine;
|
||||
|
||||
public AppNameRulerColumn(IAnnotationModel model, int width, IAnnotationAccess annotationAccess) {
|
||||
super(model, width, annotationAccess);
|
||||
}
|
||||
|
||||
public AppNameRulerColumn(int width, IAnnotationAccess annotationAccess) {
|
||||
super(width, annotationAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int line) {
|
||||
clearCurrentAnnotation();
|
||||
if (fMouseDownLine != line)
|
||||
return;
|
||||
AppNameAnnotation annotation= findAnnotation(line, true);
|
||||
if (annotation != null) {
|
||||
AppNameAnnotationModel model= (AppNameAnnotationModel) getModel();
|
||||
model.markSelected(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseDown(int rulerLine) {
|
||||
fMouseDownLine= rulerLine;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseDoubleClicked(int rulerLine) {
|
||||
if (findAnnotation(rulerLine, true) != null)
|
||||
return;
|
||||
|
||||
AppNameAnnotation annotation= findAnnotation(rulerLine, false);
|
||||
if (annotation != null) {
|
||||
AppNameAnnotationModel model= (AppNameAnnotationModel) getModel();
|
||||
model.markSelected(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app's name annotation of the column's annotation
|
||||
* model that contains the given line.
|
||||
*
|
||||
* @param line the line
|
||||
* @param exact <code>true</code> if the annotation range must match exactly
|
||||
* @return the app name annotation containing the given line
|
||||
*/
|
||||
private AppNameAnnotation findAnnotation(int line, boolean exact) {
|
||||
|
||||
AppNameAnnotation previousAnnotation= null;
|
||||
|
||||
IAnnotationModel model= getModel();
|
||||
if (model != null) {
|
||||
IDocument document= getCachedTextViewer().getDocument();
|
||||
|
||||
int previousDistance= Integer.MAX_VALUE;
|
||||
|
||||
Iterator<?> e= model.getAnnotationIterator();
|
||||
while (e.hasNext()) {
|
||||
Object next= e.next();
|
||||
if (next instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation annotation= (AppNameAnnotation) next;
|
||||
Position p= model.getPosition(annotation);
|
||||
if (p == null)
|
||||
continue;
|
||||
|
||||
int distance= getDistance(annotation, p, document, line);
|
||||
if (distance == -1)
|
||||
continue;
|
||||
|
||||
if (!exact) {
|
||||
if (distance < previousDistance) {
|
||||
previousAnnotation= annotation;
|
||||
previousDistance= distance;
|
||||
}
|
||||
} else if (distance == 0) {
|
||||
previousAnnotation= annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return previousAnnotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance of the given line to the start line of the given position in the given document. The distance is
|
||||
* <code>-1</code> when the line is not included in the given position.
|
||||
*
|
||||
* @param annotation the annotation
|
||||
* @param position the position
|
||||
* @param document the document
|
||||
* @param line the line
|
||||
* @return <code>-1</code> if line is not contained, a position number otherwise
|
||||
*/
|
||||
private int getDistance(AppNameAnnotation annotation, Position position, IDocument document, int line) {
|
||||
if (position.getOffset() > -1 && position.getLength() > -1) {
|
||||
try {
|
||||
int startLine= document.getLineOfOffset(position.getOffset());
|
||||
int endLine= document.getLineOfOffset(position.getOffset() + position.getLength());
|
||||
if (startLine <= line && line < endLine) {
|
||||
return line - startLine;
|
||||
}
|
||||
} catch (BadLocationException x) {
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean clearCurrentAnnotation() {
|
||||
if (fCurrentAnnotation != null) {
|
||||
fCurrentAnnotation.setRangeIndication(false);
|
||||
fCurrentAnnotation= null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Control createControl(CompositeRuler parentRuler, Composite parentControl) {
|
||||
Control control= super.createControl(parentRuler, parentControl);
|
||||
|
||||
// set background
|
||||
Color background= getCachedTextViewer().getTextWidget().getBackground();
|
||||
control.setBackground(background);
|
||||
|
||||
// install hover listener
|
||||
control.addMouseTrackListener(new MouseTrackAdapter() {
|
||||
public void mouseExit(MouseEvent e) {
|
||||
if (clearCurrentAnnotation())
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
|
||||
// install mouse move listener
|
||||
control.addMouseMoveListener(new MouseMoveListener() {
|
||||
public void mouseMove(MouseEvent e) {
|
||||
boolean redraw= false;
|
||||
AppNameAnnotation annotation= findAnnotation(toDocumentLineNumber(e.y), false);
|
||||
if (annotation != fCurrentAnnotation) {
|
||||
if (fCurrentAnnotation != null) {
|
||||
fCurrentAnnotation.setRangeIndication(false);
|
||||
redraw= true;
|
||||
}
|
||||
fCurrentAnnotation= annotation;
|
||||
if (fCurrentAnnotation != null) {
|
||||
fCurrentAnnotation.setRangeIndication(true);
|
||||
redraw= true;
|
||||
}
|
||||
}
|
||||
if (redraw)
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
return control;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(IAnnotationModel model) {
|
||||
if (!(model instanceof AppNameAnnotationModel) && model instanceof IAnnotationModelExtension) {
|
||||
IAnnotationModelExtension extension= (IAnnotationModelExtension) model;
|
||||
model= extension.getAnnotationModel(AppNameAnnotationModel.APP_NAME_MODEL_KEY);
|
||||
}
|
||||
super.setModel(model);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.AnnotationRulerColumn#isPropagatingMouseListener()
|
||||
*/
|
||||
protected boolean isPropagatingMouseListener() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.AnnotationRulerColumn#hasAnnotation(int)
|
||||
*/
|
||||
protected boolean hasAnnotation(int lineNumber) {
|
||||
return findAnnotation(lineNumber, true) != null;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextViewer;
|
||||
import org.eclipse.jface.text.reconciler.Reconciler;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.ast.YamlASTProvider;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
/**
|
||||
* Reconciler for Application names in CF deployment manifest YAML
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class ApplicationNameReconciler extends Reconciler {
|
||||
|
||||
private AppNameReconcilingStrategy strategy;
|
||||
|
||||
public ApplicationNameReconciler() {
|
||||
super();
|
||||
YamlASTProvider parser = new YamlASTProvider(new Yaml(new SafeConstructor()));
|
||||
strategy= new AppNameReconcilingStrategy(parser);
|
||||
this.setReconcilingStrategy(strategy, IDocument.DEFAULT_CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install(ITextViewer textViewer) {
|
||||
super.install(textViewer);
|
||||
if (textViewer instanceof ISourceViewer) {
|
||||
strategy.install((ISourceViewer)textViewer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstall() {
|
||||
super.uninstall();
|
||||
strategy.uninstall();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 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.deployment;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFApplication;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCloudDomain;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.v2.CFPushArguments;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.v2.CFRoute;
|
||||
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.deployment.DeploymentProperties;
|
||||
import org.springframework.ide.eclipse.boot.util.JavaProjectUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class CloudApplicationDeploymentProperties implements DeploymentProperties {
|
||||
|
||||
private boolean enableJmxSshTunnel;
|
||||
private List<String> boundServices;
|
||||
private Map<String, String> environmentVariables;
|
||||
private String buildpack;
|
||||
private List<String> buildpacks;
|
||||
|
||||
private int instances;
|
||||
|
||||
/*
|
||||
* URLs should never be null. If no URLs are needed, keep list empty
|
||||
*/
|
||||
private LinkedHashSet<String> urls;
|
||||
|
||||
private String appName;
|
||||
|
||||
public boolean getEnableJmxSshTunnel() {
|
||||
return enableJmxSshTunnel;
|
||||
}
|
||||
|
||||
public void setEnableJmxSshTunnel(boolean enableJmxSshTunnel) {
|
||||
this.enableJmxSshTunnel = enableJmxSshTunnel;
|
||||
}
|
||||
|
||||
private IProject project;
|
||||
|
||||
private int memory;
|
||||
|
||||
private int diskQuota;
|
||||
|
||||
private IFile manifestFile;
|
||||
|
||||
private Integer timeout;
|
||||
|
||||
private String command;
|
||||
|
||||
private String stack;
|
||||
|
||||
/**
|
||||
* Path to a zipFile containing the contents of the stuff to deploy.
|
||||
*/
|
||||
private File archive;
|
||||
private String healthCheckType;
|
||||
private String healthCheckHttpEndpoint;
|
||||
private boolean randomeRoute = false;
|
||||
|
||||
public CloudApplicationDeploymentProperties() {
|
||||
boundServices = new ArrayList<>();
|
||||
environmentVariables = new HashMap<>();
|
||||
buildpack = "";
|
||||
buildpacks = new ArrayList<>();
|
||||
instances = DeploymentProperties.DEFAULT_INSTANCES;
|
||||
urls = new LinkedHashSet<>();
|
||||
appName = null;
|
||||
project = null;
|
||||
memory = DeploymentProperties.DEFAULT_MEMORY;
|
||||
diskQuota = DeploymentProperties.DEFAULT_MEMORY;
|
||||
manifestFile = null;
|
||||
timeout = null;
|
||||
command = null;
|
||||
stack = null;
|
||||
}
|
||||
|
||||
public void setProject(IProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public IProject getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public void setMemory(int memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
public int getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
public void setDiskQuota(int diskQuota) {
|
||||
this.diskQuota = diskQuota;
|
||||
}
|
||||
|
||||
public int getDiskQuota() {
|
||||
return diskQuota;
|
||||
}
|
||||
|
||||
public void setTimeout(Integer timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public Integer getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public String getHealthCheckType() {
|
||||
return healthCheckType;
|
||||
}
|
||||
|
||||
public void setHealthCheckType(String healthCheckType) {
|
||||
this.healthCheckType = healthCheckType;
|
||||
}
|
||||
|
||||
public String getHealthCheckHttpEndpoint() {
|
||||
return healthCheckHttpEndpoint;
|
||||
}
|
||||
|
||||
public void setHealthCheckHttpEndpoint(String hche) {
|
||||
this.healthCheckHttpEndpoint = hche;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setStack(String stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
public String getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void setManifestFile(IFile file) {
|
||||
this.manifestFile = file;
|
||||
}
|
||||
|
||||
public IFile getManifestFile() {
|
||||
return this.manifestFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the list of URLs for the application
|
||||
*
|
||||
* @return never null
|
||||
*/
|
||||
public Set<String> getUris() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
public void setUris(Collection<String> urls) {
|
||||
this.urls = urls == null ? new LinkedHashSet<>() : new LinkedHashSet<>(urls);
|
||||
}
|
||||
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return this.appName;
|
||||
}
|
||||
|
||||
public void setBuildpack(String buildpack) {
|
||||
this.buildpack = buildpack;
|
||||
}
|
||||
|
||||
public void setServices(List<String> services) {
|
||||
/*
|
||||
* List should be read/write accessible hence create new instance rather
|
||||
* than use emptyList from Collections if null is passed in
|
||||
*/
|
||||
boundServices = services == null ? new ArrayList<>() : services;
|
||||
}
|
||||
|
||||
public void setBuildpacks(List<String> buildpacks) {
|
||||
this.buildpacks = buildpacks == null ? new ArrayList<>() : buildpacks;
|
||||
}
|
||||
|
||||
public void setInstances(int instances) {
|
||||
this.instances = instances;
|
||||
}
|
||||
|
||||
public void setRandomRoute(boolean randomRoute) {
|
||||
this.randomeRoute = randomRoute;
|
||||
}
|
||||
|
||||
public boolean getRandomRoute() {
|
||||
return this.randomeRoute ;
|
||||
}
|
||||
|
||||
public void setEnvironmentVariables(Map<String, String> environmentVariables) {
|
||||
/*
|
||||
* Map should be read/write accessible hence create new instance rather
|
||||
* than use emptyMap from Collections if null is passed in
|
||||
*/
|
||||
this.environmentVariables = environmentVariables == null ? new HashMap<>() : environmentVariables;
|
||||
}
|
||||
|
||||
public String getBuildpack() {
|
||||
return buildpack == null || buildpack.isEmpty() ? null : buildpack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getBuildpacks() {
|
||||
return ImmutableList.copyOf(buildpacks);
|
||||
}
|
||||
|
||||
public int getInstances() {
|
||||
return instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return never null
|
||||
*/
|
||||
public Map<String, String> getEnvironmentVariables() {
|
||||
return environmentVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return never null
|
||||
*/
|
||||
public List<String> getServices() {
|
||||
return boundServices;
|
||||
}
|
||||
|
||||
public static CloudApplicationDeploymentProperties getFor(IProject project, CloudData cloudData, CFApplication app) {
|
||||
|
||||
CloudApplicationDeploymentProperties properties = new CloudApplicationDeploymentProperties();
|
||||
|
||||
properties.setAppName(app == null ? project.getName() : app.getName());
|
||||
properties.setProject(project);
|
||||
properties.setBuildpack(app == null ? cloudData.getBuildpack() : app.getBuildpackUrl());
|
||||
|
||||
/*
|
||||
* TODO: Re-evaluate whether JAVA_OPTS need to be treated differently
|
||||
* Boot Dash Tooling adds staff to JAVA-OPTS behind the scenes. Consider
|
||||
* JAVA_OPTS env variable as the one not exposed to users
|
||||
*/
|
||||
Map<String, String> env = new LinkedHashMap<>();
|
||||
if (app != null) {
|
||||
env.putAll(app.getEnvAsMap());
|
||||
env.remove("JAVA_OPTS");
|
||||
}
|
||||
|
||||
// PT 174076433 - Support deploying of Java 11 apps to CF
|
||||
if (JavaProjectUtil.isJava11(project)) {
|
||||
env.put("JBP_CONFIG_OPEN_JDK_JRE", "{ jre: { version: 11.+}}");
|
||||
}
|
||||
|
||||
properties.setEnvironmentVariables(env);
|
||||
|
||||
properties.setInstances(app == null ? 1 : app.getInstances());
|
||||
properties.setMemory(app == null ? DeploymentProperties.DEFAULT_MEMORY : app.getMemory());
|
||||
properties.setServices(app == null ? Collections.<String>emptyList() : app.getServices());
|
||||
properties.setDiskQuota(app == null ? DeploymentProperties.DEFAULT_MEMORY : app.getDiskQuota());
|
||||
properties.setTimeout(app == null ? null : app.getTimeout());
|
||||
properties.setHealthCheckType(app==null ? null : app.getHealthCheckType());
|
||||
properties.setHealthCheckHttpEndpoint(app == null ? null : app.getHealthCheckHttpEndpoint());
|
||||
properties.setCommand(app == null ? null : app.getCommand());
|
||||
properties.setStack(app == null ? null : app.getStack());
|
||||
|
||||
if (app == null) {
|
||||
CFRoute route = CFRoute.builder().host(project.getName()).domain(cloudData.getDefaultDomain()).build();
|
||||
properties.setUris(Collections.singletonList(route.getRoute()));
|
||||
} else {
|
||||
properties.setUris(app.getUris());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public CFPushArguments toPushArguments(List<CFCloudDomain> cloudDomains) throws Exception {
|
||||
Set<String> uris = getUris();
|
||||
CFPushArguments args = new CFPushArguments();
|
||||
args.setRoutes(uris);
|
||||
args.setAppName(getAppName());
|
||||
args.setMemory(getMemory());
|
||||
args.setDiskQuota(getDiskQuota());
|
||||
args.setTimeout(getTimeout());
|
||||
args.setHealthCheckType(getHealthCheckType());
|
||||
args.setHealthCheckHttpEndpoint(getHealthCheckHttpEndpoint());
|
||||
args.setBuildpack(getBuildpack());
|
||||
args.setCommand(getCommand());
|
||||
args.setStack(getStack());
|
||||
args.setEnv(getEnvironmentVariables());
|
||||
args.setInstances(getInstances());
|
||||
args.setServices(getServices());
|
||||
args.setApplicationData(getArchive());
|
||||
args.setRandomRoute(getRandomRoute());
|
||||
return args;
|
||||
}
|
||||
|
||||
public File getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
public void setArchive(File archive) {
|
||||
this.archive = archive;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCloudDomain;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFDomainType;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFStack;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.v2.CFDomainStatus;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class CloudData {
|
||||
|
||||
private List<CFCloudDomain> domains;
|
||||
private String buildpack;
|
||||
private List<CFStack> stacks;
|
||||
|
||||
public CloudData(List<CFCloudDomain> domains, String buildpack, List<CFStack> stacks) {
|
||||
this.domains = domains;
|
||||
this.buildpack = buildpack;
|
||||
this.stacks = stacks;
|
||||
}
|
||||
|
||||
public String getBuildpack() {
|
||||
return buildpack;
|
||||
}
|
||||
|
||||
public List<CFCloudDomain> getDomains() {
|
||||
if (domains!=null) {
|
||||
return domains;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public List<CFStack> getStacks() {
|
||||
if (stacks!=null) {
|
||||
return stacks;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public String getDefaultDomain() {
|
||||
return getDomains().stream()
|
||||
.filter(d -> d.getStatus()==CFDomainStatus.SHARED && d.getType()==CFDomainType.HTTP)
|
||||
.findFirst()
|
||||
.map(d -> d.getName())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import org.eclipse.compare.CompareEditorInput;
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.jface.dialogs.DialogSettings;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.dialogs.IDialogSettings;
|
||||
import org.eclipse.jface.dialogs.IMessageProvider;
|
||||
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.dialogs.ManifestDiffDialogModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.dialogs.ManifestDiffDialogModel.Result;
|
||||
|
||||
/**
|
||||
* Dialog to compare and merge manifest file with deployment properties from CF.
|
||||
* Hosts eclipse's compare and merge editor composite.
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class ManifestDiffDialog extends TitleAreaDialog {
|
||||
|
||||
protected final CompareEditorInput fCompareEditorInput;
|
||||
private String title = "Merge Manifest File";
|
||||
|
||||
/**
|
||||
* Create a dialog to host the given input.
|
||||
* @param shell a shell
|
||||
* @param input the dialog input
|
||||
*/
|
||||
public ManifestDiffDialog(Shell shell, ManifestDiffDialogModel model) {
|
||||
super(shell);
|
||||
CompareEditorInput input = model.getInput();
|
||||
setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
|
||||
Assert.isNotNull(input);
|
||||
fCompareEditorInput= input;
|
||||
}
|
||||
|
||||
public ManifestDiffDialog(Shell shell, ManifestDiffDialogModel model, String title) {
|
||||
this(shell, model);
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
protected void createButtonsForButtonBar(Composite parent) {
|
||||
createButton(parent, IDialogConstants.YES_ID, "Use Manifest", true);
|
||||
createButton(parent, IDialogConstants.CANCEL_ID, fCompareEditorInput.getCancelButtonLabel(), false);
|
||||
createButton(parent, IDialogConstants.NO_ID, "Forget Manifest", false);
|
||||
}
|
||||
|
||||
protected Control createDialogArea(Composite parent2) {
|
||||
|
||||
Composite parent= (Composite) super.createDialogArea(parent2);
|
||||
|
||||
Control c= fCompareEditorInput.createContents(parent);
|
||||
c.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||
|
||||
Shell shell= c.getShell();
|
||||
shell.setText(fCompareEditorInput.getTitle());
|
||||
shell.setImage(fCompareEditorInput.getTitleImage());
|
||||
applyDialogFont(parent);
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
super.create();
|
||||
setTitle(title);
|
||||
if (fCompareEditorInput != null && fCompareEditorInput.getMessage() != null) {
|
||||
setMessage(fCompareEditorInput.getMessage(), IMessageProvider.WARNING);
|
||||
} else {
|
||||
setMessage(
|
||||
"Manifest file deployment properties are different from current deployment properties on CF. Please merge changes if applicable.",
|
||||
IMessageProvider.INFORMATION);
|
||||
}
|
||||
}
|
||||
|
||||
protected void buttonPressed(int buttonId) {
|
||||
switch (buttonId) {
|
||||
case IDialogConstants.NO_ID:
|
||||
fCompareEditorInput.cancelPressed();
|
||||
setReturnCode(buttonId);
|
||||
close();
|
||||
break;
|
||||
case IDialogConstants.YES_ID:
|
||||
if (fCompareEditorInput.isDirty()) {
|
||||
if (!fCompareEditorInput.okPressed())
|
||||
return;
|
||||
} else {
|
||||
fCompareEditorInput.cancelPressed();
|
||||
}
|
||||
setReturnCode(buttonId);
|
||||
close();
|
||||
break;
|
||||
case IDialogConstants.CANCEL_ID:
|
||||
fCompareEditorInput.cancelPressed();
|
||||
super.buttonPressed(buttonId);
|
||||
break;
|
||||
default:
|
||||
super.buttonPressed(buttonId);
|
||||
}
|
||||
}
|
||||
|
||||
protected IDialogSettings getDialogBoundsSettings() {
|
||||
return DialogSettings.getOrCreateSection(BootDashActivator.getDefault().getDialogSettings(), "MergeManifestDialog");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the compare editor input for this dialog.
|
||||
* @return the compare editor input for this dialog
|
||||
*/
|
||||
protected final CompareEditorInput getInput() {
|
||||
return fCompareEditorInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDialogBoundsStrategy() {
|
||||
return DIALOG_PERSISTSIZE;
|
||||
}
|
||||
|
||||
public static Result getResultForCode(int buttonId) {
|
||||
switch (buttonId) {
|
||||
case IDialogConstants.NO_ID:
|
||||
return Result.FORGET_MANIFEST;
|
||||
case IDialogConstants.YES_ID:
|
||||
return Result.USE_MANIFEST;
|
||||
case IDialogConstants.CANCEL_ID:
|
||||
return Result.CANCELED;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown button ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.deployment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class UnsupportedPushProperties {
|
||||
|
||||
|
||||
|
||||
public UnsupportedPushProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for unsupported push properties in the given deployment properties. Either allow the
|
||||
* caller of this check to continue if unsupported properties are found, or
|
||||
* cancel. If no unsupported properties are found, nothing happens.
|
||||
*
|
||||
* @param ui
|
||||
* @param cde
|
||||
* @param deploymentProperties
|
||||
* @throws OperationCanceledException if operation is cancelled
|
||||
*/
|
||||
public void allowOrCancelIfFound(UserInteractions ui,
|
||||
CloudApplicationDeploymentProperties deploymentProperties) throws OperationCanceledException {
|
||||
List<String> unsupportedProperties = findUnsupportedProperties(deploymentProperties);
|
||||
if (!unsupportedProperties.isEmpty()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(
|
||||
"The following properties are not currently supported when pushing an application to Cloud Foundry. These properties will be ignored. Continue with deployment?");
|
||||
builder.append('\n');
|
||||
|
||||
for (String prop : unsupportedProperties) {
|
||||
builder.append('\n');
|
||||
builder.append("- ");
|
||||
builder.append(prop);
|
||||
}
|
||||
if (!ui.confirmOperation("Unsupported Push Properties", builder.toString())) {
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given deployment properties for unsupported properties. Return
|
||||
* properties found that are unsupported, or empty list if nothing is found.
|
||||
*
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public List<String> findUnsupportedProperties(CloudApplicationDeploymentProperties properties) {
|
||||
if (properties != null) {
|
||||
if (properties.getBuildpacks() != null && !properties.getBuildpacks().isEmpty()) {
|
||||
return ImmutableList.of("buildpacks");
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,473 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 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.dialogs;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.equinox.security.storage.StorageException;
|
||||
import org.eclipse.jface.operation.IRunnableContext;
|
||||
import org.springframework.ide.eclipse.boot.dash.api.RunTargetType;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCredentials;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCredentials.LoginMethod;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFExceptions;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFSpace;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.ClientRequests;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CloudFoundryClientFactory;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.ops.Operation;
|
||||
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.BootDashModelContext;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.WizardModelUserInteractions;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.runtargettypes.CannotAccessPropertyException;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.runtargettypes.TargetProperties;
|
||||
import org.springframework.ide.eclipse.boot.util.Log;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.CompositeValidator;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.Validator;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Cloud Foundry Target properties that uses {@link LiveExpression} and
|
||||
* {@link Validator}.
|
||||
*/
|
||||
public class CloudFoundryTargetWizardModel {
|
||||
|
||||
private RunTargetType runTargetType;
|
||||
private BootDashModelContext context;
|
||||
|
||||
private final LiveVariable<String> url = new LiveVariable<>();
|
||||
private final LiveVariable<CFSpace> space = new LiveVariable<>();
|
||||
private final LiveVariable<Boolean> selfsigned = new LiveVariable<>(false);
|
||||
private final LiveVariable<Boolean> skipSslValidation = new LiveVariable<>(false);
|
||||
private final LiveVariable<LoginMethod> method = new LiveVariable<>(LoginMethod.PASSWORD);
|
||||
private final LiveVariable<String> userName = new LiveVariable<>();
|
||||
private final LiveVariable<String> password = new LiveVariable<>();
|
||||
private final LiveVariable<StoreCredentialsMode> storeCredentials = new LiveVariable<>(StoreCredentialsMode.STORE_NOTHING);
|
||||
|
||||
private final LiveVariable<ValidationResult> spaceResolutionStatus = new LiveVariable<>(ValidationResult.OK); // has an error if resolution failed.
|
||||
private final LiveVariable<OrgsAndSpaces> resolvedSpaces = new LiveVariable<>();
|
||||
|
||||
private String refreshToken = null;
|
||||
|
||||
private final Validator credentialsValidator = new Validator() {
|
||||
{
|
||||
dependsOn(url);
|
||||
dependsOn(userName);
|
||||
dependsOn(method);
|
||||
dependsOn(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
if (isEmpty(userName.getValue()) && method.getValue()==LoginMethod.PASSWORD) {
|
||||
return ValidationResult.info("Enter a username");
|
||||
} else if (isEmpty(url.getValue())) {
|
||||
try {
|
||||
new URL(url.getValue());
|
||||
return ValidationResult.info("Enter a target URL");
|
||||
} catch (MalformedURLException e) {
|
||||
return ValidationResult.error(e.getMessage());
|
||||
}
|
||||
} else if (method.getValue()==LoginMethod.PASSWORD) {
|
||||
if (isEmpty(password.getValue())) {
|
||||
return ValidationResult.info("Enter a password");
|
||||
}
|
||||
} else if (method.getValue()==LoginMethod.TEMPORARY_CODE) {
|
||||
if (isEmpty(password.getValue())) {
|
||||
return ValidationResult.info("Enter a Temporary Access Code");
|
||||
}
|
||||
}
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
protected boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
}
|
||||
};
|
||||
|
||||
private final Validator spaceValidator = new Validator() {
|
||||
{
|
||||
dependsOn(space);
|
||||
}
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
if (getSpaceName() == null || getOrganizationName() == null) {
|
||||
return ValidationResult.info("Select a Cloud space");
|
||||
}
|
||||
|
||||
if (space.getValue() != null) {
|
||||
RunTarget existing = CloudFoundryTargetWizardModel.this.getExistingRunTarget(space.getValue());
|
||||
if (existing != null) {
|
||||
return ValidationResult.error("A run target for that space already exists: '" + existing.getName()
|
||||
+ "'. Please select another space.");
|
||||
}
|
||||
}
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
};
|
||||
private Validator resolvedSpacesValidator = new Validator() {
|
||||
{
|
||||
dependsOn(spaceResolutionStatus);
|
||||
dependsOn(resolvedSpaces);
|
||||
}
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
ValidationResult resolveStatus = spaceResolutionStatus.getValue();
|
||||
if (!resolveStatus.isOk()) {
|
||||
return resolveStatus;
|
||||
}
|
||||
if (resolvedSpaces.getValue() == null || resolvedSpaces.getValue().getAllSpaces() == null) {
|
||||
return ValidationResult.info("Select a space to validate the credentials.");
|
||||
}
|
||||
if (resolvedSpaces.getValue().getAllSpaces().isEmpty()) {
|
||||
return ValidationResult.error(
|
||||
"No spaces available to select. Please check that the credentials and target URL are correct, and spaces are defined in the target.");
|
||||
}
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
};
|
||||
private Validator storeCredentialsValidator = PasswordDialogModel.makeStoreCredentialsValidator(method, storeCredentials);
|
||||
private CompositeValidator allPropertiesValidator = new CompositeValidator();
|
||||
|
||||
private CloudFoundryClientFactory clientFactory;
|
||||
private ImmutableSet<RunTarget> existingTargets;
|
||||
private WizardModelUserInteractions interactions;
|
||||
|
||||
|
||||
public CloudFoundryTargetWizardModel(RunTargetType runTargetType, CloudFoundryClientFactory clientFactory,
|
||||
ImmutableSet<RunTarget> existingTargets, BootDashModelContext context) {
|
||||
this(runTargetType, clientFactory, existingTargets, context, null);
|
||||
}
|
||||
|
||||
public CloudFoundryTargetWizardModel(RunTargetType runTargetType, CloudFoundryClientFactory clientFactory,
|
||||
ImmutableSet<RunTarget> existingTargets, BootDashModelContext context, WizardModelUserInteractions interactions) {
|
||||
this.runTargetType = runTargetType;
|
||||
this.context = context;
|
||||
Assert.isNotNull(clientFactory, "clientFactory should not be null");
|
||||
this.interactions = interactions;
|
||||
this.existingTargets = existingTargets == null ? ImmutableSet.<RunTarget>of() : existingTargets;
|
||||
this.clientFactory = clientFactory;
|
||||
|
||||
// Aggregate of the credentials and space validators.
|
||||
allPropertiesValidator.addChild(credentialsValidator);
|
||||
allPropertiesValidator.addChild(storeCredentialsValidator);
|
||||
allPropertiesValidator.addChild(resolvedSpacesValidator);
|
||||
allPropertiesValidator.addChild(spaceValidator);
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url.setValue(url);
|
||||
}
|
||||
|
||||
public void setSelfsigned(boolean selfsigned) {
|
||||
this.selfsigned.setValue(selfsigned);
|
||||
}
|
||||
|
||||
public void skipSslValidation(boolean skipSsl) {
|
||||
this.skipSslValidation.setValue(skipSsl);
|
||||
}
|
||||
|
||||
public void setUsername(String userName) {
|
||||
this.userName.setValue(userName);
|
||||
}
|
||||
|
||||
public void setPassword(String password) throws CannotAccessPropertyException {
|
||||
this.password.setValue(password);
|
||||
}
|
||||
|
||||
public void setSpace(CFSpace space) {
|
||||
this.space.setValue(space);
|
||||
}
|
||||
|
||||
public String getPassword() throws CannotAccessPropertyException {
|
||||
return password.getValue();
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url.getValue();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return userName.getValue();
|
||||
}
|
||||
|
||||
public void setStoreCredentials(StoreCredentialsMode store) {
|
||||
storeCredentials.setValue(store);
|
||||
}
|
||||
|
||||
public StoreCredentialsMode getStoreCredentials() {
|
||||
return storeCredentials.getValue();
|
||||
}
|
||||
|
||||
public OrgsAndSpaces resolveSpaces(IRunnableContext context) {
|
||||
try {
|
||||
boolean toFetchSpaces = true;
|
||||
OrgsAndSpaces spaces = getCloudSpaces(createTargetProperties(toFetchSpaces), context);
|
||||
resolvedSpaces.setValue(spaces);
|
||||
spaceResolutionStatus.setValue(ValidationResult.OK);
|
||||
return resolvedSpaces.getValue();
|
||||
} catch (Exception e) {
|
||||
if (CFExceptions.isAuthFailure(e) || CFExceptions.isSSLCertificateFailure(e)) {
|
||||
//don't log, its expected if user just typed bad password,
|
||||
//or didn't check ssl box when they should have.
|
||||
} else {
|
||||
Log.log(e);
|
||||
}
|
||||
resolvedSpaces.setValue(null);
|
||||
spaceResolutionStatus.setValue(ValidationResult.error(ExceptionUtil.getMessage(e)));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private OrgsAndSpaces getCloudSpaces(final CloudFoundryTargetProperties targetProperties, IRunnableContext context)
|
||||
throws Exception {
|
||||
|
||||
OrgsAndSpaces spaces = null;
|
||||
|
||||
Operation<List<CFSpace>> op = new Operation<List<CFSpace>>(
|
||||
"Connecting to the Cloud Foundry target. Please wait while the list of spaces is resolved...") {
|
||||
@Override
|
||||
protected List<CFSpace> runOp(IProgressMonitor monitor) throws Exception, OperationCanceledException {
|
||||
ClientRequests client = clientFactory.getClient(targetProperties);
|
||||
try {
|
||||
List<CFSpace> spaces = client.getSpaces();
|
||||
String t = client.getRefreshToken();
|
||||
if (t!=null) {
|
||||
refreshToken = t;
|
||||
}
|
||||
String effectiveUser = getUserName(client);
|
||||
if (effectiveUser!=null) {
|
||||
userName.setValue(effectiveUser);
|
||||
}
|
||||
return spaces;
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String getUserName(ClientRequests client) {
|
||||
try {
|
||||
return client.getUserName().block();
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
List<CFSpace> actualSpaces = op.run(context, true);
|
||||
if (actualSpaces != null && !actualSpaces.isEmpty()) {
|
||||
spaces = new OrgsAndSpaces(actualSpaces);
|
||||
}
|
||||
|
||||
return spaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create target properties based on current input values in the wizard.
|
||||
* <p>
|
||||
* Note that there are two slightly different ways to produce these properties.
|
||||
* <p>
|
||||
* a) to create a intermediate client just to fetch orgs and spaces.
|
||||
* <p>
|
||||
* b) the final properties used to create the client after space is selected and the user
|
||||
* clicks 'finish' button.
|
||||
*/
|
||||
private CloudFoundryTargetProperties createTargetProperties(boolean toFetchSpaces) throws CannotAccessPropertyException {
|
||||
CloudFoundryTargetProperties targetProps = new CloudFoundryTargetProperties(null, runTargetType, context.injections);
|
||||
if (!toFetchSpaces) {
|
||||
//Take care: when fetching spaces the space may not be known yet, so neither is the id
|
||||
String id = CloudFoundryTargetProperties.getId(
|
||||
this.getUsername(),
|
||||
this.getUrl(),
|
||||
this.getOrganizationName(),
|
||||
this.getSpaceName()
|
||||
);
|
||||
targetProps.put(TargetProperties.RUN_TARGET_ID, id);
|
||||
}
|
||||
|
||||
targetProps.setUrl(url.getValue());
|
||||
targetProps.setSelfSigned(selfsigned.getValue());
|
||||
targetProps.setSkipSslValidation(skipSslValidation.getValue());
|
||||
|
||||
targetProps.setUserName(userName.getValue());
|
||||
if (toFetchSpaces) {
|
||||
targetProps.setStoreCredentials(StoreCredentialsMode.STORE_NOTHING);
|
||||
targetProps.setCredentials(CFCredentials.fromLogin(method.getValue(), password.getValue()));
|
||||
} else {
|
||||
//use credentials of a style that is consistent with the 'store mode'.
|
||||
if (method.getValue()==LoginMethod.TEMPORARY_CODE && storeCredentials.getValue()==StoreCredentialsMode.STORE_PASSWORD) {
|
||||
//The temporary token shouldn't be stored since its meaningless. Silently downgrade storemode:
|
||||
storeCredentials.setValue(StoreCredentialsMode.STORE_NOTHING);
|
||||
}
|
||||
StoreCredentialsMode mode = storeCredentials.getValue();
|
||||
targetProps.setStoreCredentials(storeCredentials.getValue());
|
||||
switch (mode) {
|
||||
case STORE_NOTHING:
|
||||
case STORE_TOKEN:
|
||||
Assert.isTrue(refreshToken!=null);
|
||||
targetProps.setCredentials(CFCredentials.fromRefreshToken(refreshToken));
|
||||
break;
|
||||
case STORE_PASSWORD:
|
||||
targetProps.setCredentials(CFCredentials.fromPassword(password.getValue()));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("BUG: Missing switch case?");
|
||||
}
|
||||
}
|
||||
targetProps.setSpace(space.getValue());
|
||||
return targetProps;
|
||||
}
|
||||
|
||||
public OrgsAndSpaces getSpaces() {
|
||||
return resolvedSpaces.getValue();
|
||||
}
|
||||
|
||||
protected RunTarget getExistingRunTarget(CFSpace space) {
|
||||
if (space != null) {
|
||||
String targetId = CloudFoundryTargetProperties.getId(getUsername(), getUrl(),
|
||||
space.getOrganization().getName(), space.getName());
|
||||
for (RunTarget target : existingTargets) {
|
||||
if (targetId.equals(target.getId())) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public CloudFoundryRunTarget finish() throws Exception {
|
||||
CloudFoundryTargetProperties targetProps = null;
|
||||
try {
|
||||
targetProps = createTargetProperties(/*toFetchSpaces*/false);
|
||||
} catch (Exception e) {
|
||||
final StorageException storageException = getStorageException(e);
|
||||
// Allow run target to be created on storage exceptions as the run target can still be created and connected
|
||||
if (storageException != null) {
|
||||
Log.log(storageException);
|
||||
if (interactions != null) {
|
||||
String message = "Failed to store credentials in secure storage. Please check your secure storage preferences. Error: "
|
||||
+ storageException.getMessage();
|
||||
interactions.informationPopup("Secure Storage Error", message);
|
||||
}
|
||||
storeCredentials.setValue(StoreCredentialsMode.STORE_NOTHING);
|
||||
targetProps = createTargetProperties(/*toFetchSpaces*/false);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return (CloudFoundryRunTarget) runTargetType.createRunTarget(targetProps);
|
||||
}
|
||||
|
||||
public String getSpaceName() {
|
||||
CFSpace space = this.space.getValue();
|
||||
if (space!=null) {
|
||||
return space.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOrganizationName() {
|
||||
CFSpace space = this.space.getValue();
|
||||
if (space!=null) {
|
||||
return space.getOrganization().getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected StorageException getStorageException(Exception e) {
|
||||
if (e instanceof StorageException) {
|
||||
return (StorageException) e;
|
||||
}
|
||||
if (e.getCause() instanceof StorageException) {
|
||||
return (StorageException) e.getCause();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A 'complete' validator that reflects the validation state of all the inputs in this 'ui'.
|
||||
*/
|
||||
public LiveExpression<ValidationResult> getValidator() {
|
||||
return allPropertiesValidator;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public LiveVariable<LoginMethod> getMethodVar() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public LiveVariable<String> getUserNameVar() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public LiveVariable<String> getPasswordVar() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public LiveVariable<StoreCredentialsMode> getStoreVar() {
|
||||
return storeCredentials;
|
||||
}
|
||||
|
||||
public LiveVariable<Boolean> getSkipSslVar() {
|
||||
return skipSslValidation;
|
||||
}
|
||||
|
||||
public LiveVariable<String> getUrlVar() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public LiveVariable<CFSpace> getSpaceVar() {
|
||||
return space;
|
||||
}
|
||||
|
||||
public LiveExpression<Boolean> getEnableSpacesUI() {
|
||||
return credentialsValidator.apply((r) -> r.isOk());
|
||||
}
|
||||
|
||||
public LiveExpression<Boolean> getEnableUserName() {
|
||||
return method.apply((method) -> method==LoginMethod.PASSWORD);
|
||||
}
|
||||
|
||||
public LiveExpression<ValidationResult> getSpaceValidator() {
|
||||
return spaceValidator;
|
||||
}
|
||||
|
||||
public LiveExpression<ValidationResult> getResolvedSpacesValidator() {
|
||||
return resolvedSpacesValidator;
|
||||
}
|
||||
|
||||
public LiveExpression<ValidationResult> getCredentialsValidator() {
|
||||
return credentialsValidator;
|
||||
}
|
||||
|
||||
public void setMethod(LoginMethod v) {
|
||||
method.setValue(v);
|
||||
}
|
||||
|
||||
public Validator getStoreCredentialsValidator() {
|
||||
return storeCredentialsValidator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.dialogs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.layout.GridLayoutFactory;
|
||||
import org.eclipse.jface.wizard.WizardDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFCredentials.LoginMethod;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.runtarget.CloudFoundryRunTarget;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunTarget;
|
||||
import org.springframework.ide.eclipse.editor.support.util.CollectionUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.CompositeValidator;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.CheckboxSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.ChooseOneSectionCombo;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.IPageWithSections;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.StringFieldSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.UIConstants;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.ValidatorSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.WizardPageSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.WizardPageWithSections;
|
||||
|
||||
/**
|
||||
* Creates a Cloud Foundry target by prompting user for credentials and Cloud
|
||||
* Foundry target URL.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class CloudFoundryTargetWizardPage extends WizardPageWithSections {
|
||||
|
||||
private CloudFoundryTargetWizardModel model;
|
||||
|
||||
private class SelectSpaceSection extends WizardPageSection {
|
||||
|
||||
private CompositeValidator spaceSectionValidator = new CompositeValidator();
|
||||
{
|
||||
//Do these two really need to be exposed from the model as separate entities?
|
||||
// I don't think they are really used separately?
|
||||
// Keeping it like this for now as it sort of make sense. The ui here has two pieces
|
||||
// one is a box showing a selected space. And the other a button to resolve spaces.
|
||||
spaceSectionValidator.addChild(model.getResolvedSpacesValidator());
|
||||
spaceSectionValidator.addChild(model.getSpaceValidator());
|
||||
}
|
||||
|
||||
public SelectSpaceSection(IPageWithSections owner) {
|
||||
super(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createContents(Composite page) {
|
||||
Composite buttonComposite = new Composite(page, SWT.NONE);
|
||||
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonComposite);
|
||||
GridLayout layout = GridLayoutFactory.fillDefaults().numColumns(3).margins(0,2).create();
|
||||
buttonComposite.setLayout(layout);
|
||||
|
||||
Label label = new Label(buttonComposite, SWT.NONE);
|
||||
label.setText("Space:");
|
||||
GridDataFactory.fillDefaults()
|
||||
.hint(UIConstants.fieldLabelWidthHint(label), SWT.DEFAULT)
|
||||
.align(SWT.BEGINNING, SWT.CENTER)
|
||||
.applyTo(label);
|
||||
|
||||
Text spaceValueText = new Text(buttonComposite, SWT.BORDER);
|
||||
spaceValueText.setEnabled(false);
|
||||
spaceValueText.setBackground(buttonComposite.getBackground());
|
||||
GridDataFactory.fillDefaults().grab(true, false).applyTo(spaceValueText);
|
||||
model.getSpaceVar().addListener((exp, value) -> {
|
||||
if (spaceValueText != null && !spaceValueText.isDisposed()) {
|
||||
spaceValueText.setText(value != null ? value.getName() : "");
|
||||
}
|
||||
});
|
||||
|
||||
Button selectSpaceButton = new Button(buttonComposite, SWT.PUSH);
|
||||
selectSpaceButton.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
|
||||
selectSpaceButton.setText("Select Space...");
|
||||
selectSpaceButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent event) {
|
||||
|
||||
// Fetch an updated list of orgs and spaces in a cancellable
|
||||
// operation (i.e. the operation
|
||||
// can be cancelled in the wizard's progress bar)
|
||||
model.resolveSpaces(getWizard().getContainer());
|
||||
OrgsAndSpaces spaces = model.getSpaces();
|
||||
if (spaces != null && CollectionUtil.hasElements(spaces.getAllSpaces())) {
|
||||
OrgsAndSpacesWizard spacesWizard = new OrgsAndSpacesWizard(model);
|
||||
WizardDialog dialog = new WizardDialog(getShell(), spacesWizard);
|
||||
dialog.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Enable the "Select Space" button once credentials are complete.
|
||||
model.getCredentialsValidator().addListener((exp, value) -> {
|
||||
if (selectSpaceButton != null && !selectSpaceButton.isDisposed()) {
|
||||
selectSpaceButton.setEnabled(value.isOk());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveExpression<ValidationResult> getValidator() {
|
||||
return spaceSectionValidator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private CloudFoundryRunTarget runTarget = null;
|
||||
|
||||
public CloudFoundryTargetWizardPage(CloudFoundryTargetWizardModel model) {
|
||||
super("page1", "Add a Cloud Foundry Target", BootDashActivator.getImageDescriptor("icons/wizban_cloudfoundry.png"));
|
||||
this.model = model;
|
||||
setDescription("Enter credentials and a Cloud Foundry target URL.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<WizardPageSection> createSections() {
|
||||
List<WizardPageSection> sections = new ArrayList<>();
|
||||
sections.add(new ChooseOneSectionCombo<>(this, "Method:", model.getMethodVar(), EnumSet.allOf(LoginMethod.class)));
|
||||
//TODO: hide password or passcode field depending on the method.
|
||||
sections.add(new StringFieldSection(this, "Email:", model.getUserNameVar())
|
||||
.setEnabler(model.getEnableUserName()));
|
||||
|
||||
sections.add(new StringFieldSection(this, "Password:", model.getPasswordVar()).setPassword(true));
|
||||
sections.add(UpdatePasswordDialog.storeCredentialsSection(this, model.getStoreVar(), model.getStoreCredentialsValidator()));
|
||||
sections.add(new StringFieldSection(this, "Url:", model.getUrlVar()));
|
||||
sections.add(new ValidatorSection(model.getCredentialsValidator(), this));
|
||||
sections.add(new SelectSpaceSection(this));
|
||||
sections.add(new CheckboxSection(this, model.getSkipSslVar(), "Skip SSL Validation"));
|
||||
return sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a run target ONCE.
|
||||
* @return created run target. Returns cached target if already created.
|
||||
*/
|
||||
public CloudFoundryRunTarget createRunTarget() {
|
||||
// Cache to avoid creating run target multiple times in the same wizard session
|
||||
if (runTarget == null) {
|
||||
try {
|
||||
runTarget = model.finish();
|
||||
} catch (Exception e) {
|
||||
setErrorMessage(e.getMessage());
|
||||
}
|
||||
}
|
||||
return runTarget;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.dialogs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.ButtonSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.DialogWithSections;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.StringFieldSection;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.WizardPageSection;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class CustomizeAppsManagerURLDialog extends DialogWithSections {
|
||||
|
||||
private CustomizeAppsManagerURLDialogModel model;
|
||||
|
||||
public CustomizeAppsManagerURLDialog(CustomizeAppsManagerURLDialogModel model, Shell shell) {
|
||||
super("Customize Host URL of Apps Manager", model, shell);
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<WizardPageSection> createSections() throws CoreException {
|
||||
Builder<WizardPageSection> sections = ImmutableList.builder();
|
||||
sections.add(new StringFieldSection(this, model.host).tooltip(model.getHelpText()));
|
||||
sections.add(new ButtonSection(this, "Restore Defaults", model.restoreDefaultsHandler));
|
||||
return sections.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.dialogs;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.model.CloudFoundryBootDashModel;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.StringFieldModel;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.OkButtonHandler;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class CustomizeAppsManagerURLDialogModel implements OkButtonHandler {
|
||||
|
||||
public final StringFieldModel host = new StringFieldModel("Apps Manager", "");
|
||||
private final CloudFoundryBootDashModel cloudFoundrySection;
|
||||
|
||||
public CustomizeAppsManagerURLDialogModel(CloudFoundryBootDashModel cloudFoundrySection) {
|
||||
this.cloudFoundrySection = cloudFoundrySection;
|
||||
host.getVariable().setValue(this.cloudFoundrySection.getRunTarget().getAppsManagerHost());
|
||||
}
|
||||
|
||||
public Callable<Void> restoreDefaultsHandler = new Callable<Void>() {
|
||||
public Void call() throws Exception {
|
||||
host.getVariable().setValue(getDefaultValue());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void performOk() throws Exception {
|
||||
cloudFoundrySection.getRunTarget().setAppsManagerHost(host.getValue());
|
||||
cloudFoundrySection.notifyModelStateChanged();
|
||||
}
|
||||
|
||||
public String getHelpText() {
|
||||
return "no help available";
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return cloudFoundrySection.getRunTarget().getAppsManagerHostDefault();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,705 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.dialogs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.commands.AbstractHandler;
|
||||
import org.eclipse.core.commands.ExecutionEvent;
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
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.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jface.dialogs.DialogSettings;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.dialogs.IDialogSettings;
|
||||
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.resource.JFaceResources;
|
||||
import org.eclipse.jface.text.source.SourceViewer;
|
||||
import org.eclipse.jface.text.source.projection.ProjectionViewer;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.ISelectionChangedListener;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.ITreeSelection;
|
||||
import org.eclipse.jface.viewers.SelectionChangedEvent;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.jface.viewers.TreeViewer;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.jface.viewers.ViewerFilter;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Combo;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Sash;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IWorkbenchCommandConstants;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.handlers.IHandlerActivation;
|
||||
import org.eclipse.ui.handlers.IHandlerService;
|
||||
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
|
||||
import org.eclipse.ui.model.WorkbenchLabelProvider;
|
||||
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
|
||||
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.dialogs.DeploymentPropertiesDialogModel.ManifestType;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.UIValueListener;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.util.SwtConnect;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.Log;
|
||||
|
||||
/**
|
||||
* Cloud Foundry Application deployment properties dialog. Allows user to select
|
||||
* manifest YAML file or enter deployment manifest YAML manually.
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class DeploymentPropertiesDialog extends TitleAreaDialog {
|
||||
|
||||
public static final String CONTEXT_DEPLOYMENT_PROPERTIES_DIALOG = "deployment-properties-dialog";
|
||||
|
||||
final static private String DIALOG_LIST_HEIGHT_SETTING = "ManifestFileDialog.listHeight"; //$NON-NLS-1$
|
||||
final static private String YML_EXTENSION = "yml"; //$NON-NLS-1$
|
||||
final static private String[] FILE_FILTER_NAMES = new String[] {"Manifest YAML files - *manifest*.yml", "YAML files - *.yml", "All files - *.*"};
|
||||
|
||||
|
||||
private static abstract class DeepFileFilter extends ViewerFilter {
|
||||
|
||||
@Override
|
||||
public boolean select(Viewer viewer, Object parent, Object element) {
|
||||
if (element instanceof IResource && !((IResource)element).isDerived()) {
|
||||
if (element instanceof IFile) {
|
||||
return acceptFile((IFile)element);
|
||||
}
|
||||
if (element instanceof IContainer) {
|
||||
try {
|
||||
IContainer container = (IContainer) element;
|
||||
for (IResource resource : container.members()) {
|
||||
boolean select = select(viewer, container, resource);
|
||||
if (select) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract protected boolean acceptFile(IFile file);
|
||||
|
||||
}
|
||||
|
||||
final static private ViewerFilter YAML_FILE_FILTER = new DeepFileFilter() {
|
||||
@Override
|
||||
protected boolean acceptFile(IFile file) {
|
||||
return YML_EXTENSION.equals(file.getFileExtension());
|
||||
}
|
||||
};
|
||||
final static private ViewerFilter MANIFEST_YAML_FILE_FILTER = new DeepFileFilter() {
|
||||
@Override
|
||||
protected boolean acceptFile(IFile file) {
|
||||
return file.getName().toLowerCase().contains("manifest") && YML_EXTENSION.equals(file.getFileExtension());
|
||||
}
|
||||
};
|
||||
final static private ViewerFilter ALL_FILES = new ViewerFilter() {
|
||||
@Override
|
||||
public boolean select(Viewer viewer, Object parent, Object element) {
|
||||
return (element instanceof IResource) && !((IResource)element).isDerived();
|
||||
}
|
||||
};
|
||||
final static private ViewerFilter[][] RESOURCE_FILTERS = new ViewerFilter[][] {
|
||||
{MANIFEST_YAML_FILE_FILTER},
|
||||
{YAML_FILE_FILTER},
|
||||
{ALL_FILES}
|
||||
};
|
||||
|
||||
final static private int DEFAULT_WORKSPACE_GROUP_HEIGHT = 200;
|
||||
|
||||
private Label fileLabel;
|
||||
private Sash resizeSash;
|
||||
private TreeViewer workspaceViewer;
|
||||
private Button refreshButton;
|
||||
private Button buttonFileManifest;
|
||||
private Button buttonManualManifest;
|
||||
private Group fileGroup;
|
||||
private Group yamlGroup;
|
||||
private Composite fileYamlComposite;
|
||||
private Composite manualYamlComposite;
|
||||
private Combo fileFilterCombo;
|
||||
private IHandlerService service;
|
||||
private List<IHandlerActivation> activations;
|
||||
private EditorActionHandler[] handlers = new EditorActionHandler[] {
|
||||
new EditorActionHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, SourceViewer.CONTENTASSIST_PROPOSALS),
|
||||
new EditorActionHandler(IWorkbenchCommandConstants.EDIT_UNDO, SourceViewer.UNDO),
|
||||
new EditorActionHandler(IWorkbenchCommandConstants.EDIT_REDO, SourceViewer.REDO),
|
||||
};
|
||||
|
||||
private ISelectionChangedListener selectionListener = new ISelectionChangedListener() {
|
||||
@Override
|
||||
public void selectionChanged(final SelectionChangedEvent e) {
|
||||
IResource resource = (IResource) getStructuredSelection(workspaceViewer).getFirstElement();
|
||||
model.setSelectedManifest(resource);
|
||||
}
|
||||
};
|
||||
|
||||
final private DeploymentPropertiesDialogModel model;
|
||||
private Button buttonEnableJmx;
|
||||
|
||||
public DeploymentPropertiesDialog(Shell parentShell, DeploymentPropertiesDialogModel model) {
|
||||
super(parentShell);
|
||||
this.model = model;
|
||||
this.service = (IHandlerService) PlatformUI.getWorkbench().getAdapter(IHandlerService.class);
|
||||
this.activations = new ArrayList<>(handlers.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
setTitle("Select Deployment Manifest for project '" + model.getProjectName() + "'");
|
||||
Composite container = (Composite) super.createDialogArea(parent);
|
||||
final Composite composite = new Composite(container, parent.getStyle());
|
||||
composite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
composite.setLayout(new GridLayout());
|
||||
|
||||
createModeSwitchGroup(composite);
|
||||
|
||||
createFileGroup(composite);
|
||||
|
||||
createResizeSash(composite);
|
||||
|
||||
createYamlContentsGroup(composite);
|
||||
|
||||
if (model.supportsSsh) {
|
||||
createJmxSshOptionsGroup(composite);
|
||||
}
|
||||
|
||||
activateHandlers();
|
||||
|
||||
model.type.addListener(new ValueListener<ManifestType>() {
|
||||
@Override
|
||||
public void gotValue(LiveExpression<ManifestType> exp, ManifestType type) {
|
||||
GridData gridData;
|
||||
boolean isFile = type == ManifestType.FILE;
|
||||
buttonFileManifest.setSelection(isFile);
|
||||
buttonManualManifest.setSelection(!isFile);
|
||||
|
||||
refreshButton.setEnabled(isFile && !workspaceViewer.getSelection().isEmpty());
|
||||
workspaceViewer.getControl().setEnabled(isFile);
|
||||
fileLabel.setEnabled(isFile);
|
||||
|
||||
gridData = GridDataFactory.copyData((GridData) fileGroup.getLayoutData());
|
||||
gridData.exclude = !isFile;
|
||||
fileGroup.setVisible(isFile);
|
||||
fileGroup.setLayoutData(gridData);
|
||||
gridData = GridDataFactory.copyData((GridData) resizeSash.getLayoutData());
|
||||
gridData.exclude = !isFile;
|
||||
resizeSash.setVisible(isFile);
|
||||
resizeSash.setLayoutData(gridData);
|
||||
fileGroup.getParent().layout();
|
||||
|
||||
fileYamlComposite.setVisible(isFile);
|
||||
gridData = GridDataFactory.copyData((GridData) fileYamlComposite.getLayoutData());
|
||||
gridData.exclude = !isFile;
|
||||
fileYamlComposite.setLayoutData(gridData);
|
||||
manualYamlComposite.setVisible(!isFile);
|
||||
gridData = GridDataFactory.copyData((GridData) manualYamlComposite.getLayoutData());
|
||||
gridData.exclude = isFile;
|
||||
manualYamlComposite.setLayoutData(gridData);
|
||||
yamlGroup.layout();
|
||||
yamlGroup.getParent().layout();
|
||||
}
|
||||
});
|
||||
|
||||
model.getValidator().addListener(new UIValueListener<ValidationResult>() {
|
||||
@Override
|
||||
protected void uiGotValue(LiveExpression<ValidationResult> exp, ValidationResult value) {
|
||||
ValidationResult result = exp.getValue();
|
||||
if (getButton(IDialogConstants.OK_ID) != null) {
|
||||
getButton(IDialogConstants.OK_ID).setEnabled(result.status != IStatus.ERROR);
|
||||
}
|
||||
setMessage(result.msg, result.getMessageProviderStatus());
|
||||
}
|
||||
});
|
||||
|
||||
parent.pack(true);
|
||||
|
||||
/*
|
||||
* Reveal the selected manifest file in the workspace viewer now when
|
||||
* controls are created and laid out
|
||||
*/
|
||||
if (!workspaceViewer.getSelection().isEmpty()) {
|
||||
workspaceViewer.setSelection(workspaceViewer.getSelection(), true);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
private void createJmxSshOptionsGroup(Composite composite) {
|
||||
Group group = new Group(composite, SWT.NONE);
|
||||
group.setText("JMX Ssh Tunnel");
|
||||
group.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
|
||||
group.setLayout(new GridLayout(2, true));
|
||||
|
||||
buttonEnableJmx = new Button(group, SWT.CHECK);
|
||||
buttonEnableJmx.setText("Enable");
|
||||
buttonEnableJmx.setToolTipText("Activate JMX on the deployed app and create an SSH tunnel to it so it can be accessed locally.");
|
||||
|
||||
SwtConnect.checkbox(buttonEnableJmx, model.enableJmxSshTunnel);
|
||||
}
|
||||
|
||||
private void createModeSwitchGroup(Composite composite) {
|
||||
Group typeGroup = new Group(composite, SWT.NONE);
|
||||
typeGroup.setText("Manifest Type");
|
||||
typeGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
|
||||
typeGroup.setLayout(new GridLayout(2, true));
|
||||
|
||||
buttonFileManifest = new Button(typeGroup, SWT.RADIO);
|
||||
buttonFileManifest.setText("File");
|
||||
buttonFileManifest.setSelection(model.isFileManifestType());
|
||||
buttonFileManifest.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
if (buttonFileManifest.getSelection()) {
|
||||
model.setManifestType(ManifestType.FILE);
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonFileManifest.setLayoutData(GridDataFactory.fillDefaults().create());
|
||||
|
||||
buttonManualManifest = new Button(typeGroup, SWT.RADIO);
|
||||
buttonManualManifest.setText("Manual");
|
||||
buttonManualManifest.setSelection(model.isManualManifestType());
|
||||
buttonManualManifest.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
if (buttonManualManifest.getSelection()) {
|
||||
model.setManifestType(ManifestType.MANUAL);
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonManualManifest.setLayoutData(GridDataFactory.fillDefaults().create());
|
||||
}
|
||||
|
||||
private void createFileGroup(Composite composite) {
|
||||
fileGroup = new Group(composite, SWT.NONE);
|
||||
fileGroup.setText("Workspace File");
|
||||
fileGroup.setLayout(new GridLayout(2, false));
|
||||
int height = DEFAULT_WORKSPACE_GROUP_HEIGHT;
|
||||
try {
|
||||
height = getDialogBoundsSettings().getInt(DIALOG_LIST_HEIGHT_SETTING);
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore exception
|
||||
}
|
||||
fileGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, height).create());
|
||||
|
||||
workspaceViewer = new TreeViewer(fileGroup);
|
||||
workspaceViewer.setContentProvider(new BaseWorkbenchContentProvider() {
|
||||
|
||||
@Override
|
||||
public Object[] getChildren(Object element) {
|
||||
Object[] children = super.getChildren(element);
|
||||
if (element instanceof IFolder) {
|
||||
IFolder folder = (IFolder) element;
|
||||
if (folder.getParent() instanceof IProject) {
|
||||
if (".settings".equals(folder.getName())) {
|
||||
List<Object> filtered = new ArrayList<>();
|
||||
for (Object child : children) {
|
||||
if (child instanceof IFile) {
|
||||
// Skip the temporary manifest file for manual mode
|
||||
IFile f = (IFile) child;
|
||||
if (DeploymentPropertiesDialogModel.DUMMY_MANUAL_MANIFEST_YML.equals(f.getName())
|
||||
|| DeploymentPropertiesDialogModel.DUMMY_FILE_MANIFEST_YML.equals(f.getName())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
filtered.add(child);
|
||||
}
|
||||
children = filtered.toArray(new Object[filtered.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (element instanceof IProject) {
|
||||
IJavaProject javaProject = JavaCore.create((IProject)element);
|
||||
if (javaProject != null) {
|
||||
List<Object> filtered = new ArrayList<>();
|
||||
for (Object child : children) {
|
||||
// Filter out obvious output folders
|
||||
if (child instanceof IFolder) {
|
||||
IFolder folder = (IFolder) child;
|
||||
if ("target".equals(folder.getName()) || "bin".equals(folder.getName())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
filtered.add(child);
|
||||
}
|
||||
children = filtered.toArray(new Object[filtered.size()]);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
});
|
||||
workspaceViewer.setLabelProvider(new WorkbenchLabelProvider());
|
||||
workspaceViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
|
||||
workspaceViewer.getControl().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
|
||||
/*
|
||||
* Do not set the selection based on manifest file changes outside of UI. Bad. SWT doesn't like it.
|
||||
*/
|
||||
if (model.getSelectedManifest() != null) {
|
||||
workspaceViewer.setSelection(new StructuredSelection(new Object[] { model.getSelectedManifest() }), true);
|
||||
}
|
||||
|
||||
workspaceViewer.addSelectionChangedListener(selectionListener);
|
||||
|
||||
Composite fileButtonsComposite = new Composite(fileGroup, SWT.NONE);
|
||||
GridLayout layout = new GridLayout();
|
||||
layout.marginHeight = 0;
|
||||
layout.marginWidth = 0;
|
||||
layout.horizontalSpacing = 0;
|
||||
layout.verticalSpacing = 0;
|
||||
fileButtonsComposite.setLayout(layout);
|
||||
fileButtonsComposite.setLayoutData(GridDataFactory.fillDefaults().create());
|
||||
|
||||
refreshButton = new Button(fileButtonsComposite, SWT.PUSH);
|
||||
refreshButton.setImage(BootDashActivator.getDefault().getImageRegistry().get(BootDashActivator.REFRESH_ICON));
|
||||
refreshButton.setText("Refresh");
|
||||
refreshButton.setEnabled(false);
|
||||
refreshButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
refreshManifests();
|
||||
}
|
||||
});
|
||||
refreshButton.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
|
||||
|
||||
fileFilterCombo = new Combo(fileGroup, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
|
||||
fileFilterCombo.setItems(FILE_FILTER_NAMES);
|
||||
int selectionIndex = 0;
|
||||
|
||||
IResource manifestFile = model.getSelectedManifest();
|
||||
if (manifestFile != null) {
|
||||
selectionIndex = RESOURCE_FILTERS.length - 1;
|
||||
for (int i = 0; i < RESOURCE_FILTERS.length; i++) {
|
||||
boolean accept = true;
|
||||
for (ViewerFilter filter : RESOURCE_FILTERS[i]) {
|
||||
accept = filter.select(null, null, manifestFile);
|
||||
if (!accept) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (accept) {
|
||||
selectionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
workspaceViewer.setFilters(RESOURCE_FILTERS[selectionIndex]);
|
||||
fileFilterCombo.select(selectionIndex);
|
||||
fileFilterCombo.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
// Remove selection listener to set selection from current pathModel value
|
||||
workspaceViewer.removeSelectionChangedListener(selectionListener);
|
||||
workspaceViewer.setFilters(RESOURCE_FILTERS[fileFilterCombo.getSelectionIndex()]);
|
||||
// Add the selection listener back after the initial value has been set
|
||||
workspaceViewer.addSelectionChangedListener(selectionListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createResizeSash(Composite composite) {
|
||||
resizeSash = new Sash(composite, SWT.HORIZONTAL);
|
||||
resizeSash.setLayoutData(GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 4).grab(true, false).create());
|
||||
resizeSash.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
GridData listLayoutData = (GridData) fileGroup.getLayoutData();
|
||||
int newHeight = listLayoutData.heightHint + e.y - resizeSash.getBounds().y;
|
||||
if (newHeight < listLayoutData.minimumHeight) {
|
||||
newHeight = listLayoutData.minimumHeight;
|
||||
e.doit = false;
|
||||
}
|
||||
listLayoutData.heightHint = newHeight;
|
||||
fileGroup.setLayoutData(listLayoutData);
|
||||
fileGroup.getParent().layout();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createYamlContentsGroup(Composite composite) {
|
||||
yamlGroup = new Group(composite, SWT.NONE);
|
||||
yamlGroup.setText("YAML Content");
|
||||
yamlGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
yamlGroup.setLayout(new GridLayout());
|
||||
|
||||
fileYamlComposite = new Composite(yamlGroup, SWT.NONE);
|
||||
fileYamlComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
GridLayout layout = new GridLayout(3, false);
|
||||
layout.marginWidth = 0;
|
||||
fileYamlComposite.setLayout(layout);
|
||||
|
||||
fileLabel = new Label(fileYamlComposite, SWT.WRAP);
|
||||
fileLabel.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).span(3, SWT.DEFAULT).create());
|
||||
|
||||
model.getFileLabel().addListener(new UIValueListener<String>() {
|
||||
@Override
|
||||
protected void uiGotValue(LiveExpression<String> exp, String value) {
|
||||
if (!fileLabel.isDisposed()) {
|
||||
fileLabel.setText(exp.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
model.getFileYamlEditor().setContext(CONTEXT_DEPLOYMENT_PROPERTIES_DIALOG);
|
||||
try {
|
||||
model.getFileYamlEditor().createControl(fileYamlComposite);
|
||||
} catch (CoreException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
model.getFileYamlEditor().getViewer().getControl().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 200).create());
|
||||
model.fileYamlEditorControlCreated();
|
||||
|
||||
|
||||
manualYamlComposite = new Composite(yamlGroup, SWT.NONE);
|
||||
manualYamlComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
layout = new GridLayout();
|
||||
layout.marginWidth = 0;
|
||||
manualYamlComposite.setLayout(layout);
|
||||
|
||||
Label manualYamlDescriptionLabel = new Label(manualYamlComposite, SWT.WRAP);
|
||||
manualYamlDescriptionLabel.setText(model.isManualManifestReadOnly() ? "Preview of the contents of the auto-generated deployment manifest:" : "Edit deployment manifest contents:");
|
||||
manualYamlDescriptionLabel.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
|
||||
|
||||
|
||||
model.getManualYamlEditor().setContext(CONTEXT_DEPLOYMENT_PROPERTIES_DIALOG);
|
||||
try {
|
||||
model.getManualYamlEditor().createControl(manualYamlComposite);
|
||||
} catch (CoreException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
model.getManualYamlEditor().getViewer().getControl().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 200).create());
|
||||
ProjectionViewer manualYamlViewer = model.getManualYamlEditor().getViewer();
|
||||
if (model.isManualManifestReadOnly()) {
|
||||
manualYamlViewer.setEditable(false);
|
||||
manualYamlViewer.getTextWidget().setCaret(null);
|
||||
manualYamlViewer.getTextWidget().setCursor(getShell().getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
|
||||
}
|
||||
model.manualYamlEditorControlCreated();
|
||||
|
||||
/*
|
||||
* Set the proper Font on the YAML viewers
|
||||
*/
|
||||
model.getFileYamlEditor().getViewer().getTextWidget().setFont(JFaceResources.getTextFont());
|
||||
manualYamlViewer.getTextWidget().setFont(JFaceResources.getTextFont());
|
||||
}
|
||||
|
||||
private void activateHandlers() {
|
||||
if (service != null) {
|
||||
for (EditorActionHandler handler : handlers) {
|
||||
activations.add(service.activateHandler(handler.getActionId(), handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deactivateHandlers() {
|
||||
if (service != null) {
|
||||
for (IHandlerActivation activation : activations) {
|
||||
service.deactivateHandler(activation);
|
||||
}
|
||||
activations.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshManifests() {
|
||||
IResource selectedResource = (IResource) ((IStructuredSelection) workspaceViewer.getSelection()).getFirstElement();
|
||||
final IResource resourceToRefresh = selectedResource instanceof IFile ? selectedResource.getParent() : selectedResource;
|
||||
Job job = new Job("Refreshing resources for '" + resourceToRefresh.getName() + "'") {
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
IStatus status = Status.OK_STATUS;
|
||||
try {
|
||||
resourceToRefresh.refreshLocal(IResource.DEPTH_INFINITE, monitor);
|
||||
} catch (CoreException e) {
|
||||
status = e.getStatus();
|
||||
}
|
||||
getParentShell().getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Remove selection listener to set selection from current pathModel value
|
||||
workspaceViewer.removeSelectionChangedListener(selectionListener);
|
||||
workspaceViewer.refresh(resourceToRefresh);
|
||||
// Add the selection listener back after the initial value has been set
|
||||
workspaceViewer.addSelectionChangedListener(selectionListener);
|
||||
}
|
||||
});
|
||||
return status;
|
||||
}
|
||||
};
|
||||
job.setRule(resourceToRefresh);
|
||||
job.schedule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isResizable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDialogSettings getDialogBoundsSettings() {
|
||||
return DialogSettings.getOrCreateSection(BootDashActivator.getDefault().getDialogSettings(), "ManifestFileDialog");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
if (getReturnCode() == IDialogConstants.CANCEL_ID) {
|
||||
model.cancelPressed();
|
||||
} else {
|
||||
if (!model.okPressed()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
getDialogBoundsSettings().put(DIALOG_LIST_HEIGHT_SETTING, ((GridData)fileGroup.getLayoutData()).heightHint);
|
||||
boolean close = super.close();
|
||||
dispose();
|
||||
return close;
|
||||
}
|
||||
|
||||
protected void dispose() {
|
||||
/*
|
||||
* Deactivate handlers for key bindings
|
||||
*/
|
||||
deactivateHandlers();
|
||||
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
// TODO: this should be replaced with TreeViewer.getStructuredSelection once we drop support for Eclipse 4.4
|
||||
// the TreeViewer.getStructuredSelection() API got introduced in Eclipse 4.5
|
||||
private ITreeSelection getStructuredSelection(TreeViewer treeViewer) {
|
||||
ISelection selection = treeViewer.getSelection();
|
||||
if (selection instanceof ITreeSelection) {
|
||||
return (ITreeSelection) selection;
|
||||
}
|
||||
throw new ClassCastException("AbstractTreeViewer should return an instance of ITreeSelection from its getSelection() method."); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDialogBoundsStrategy() {
|
||||
return DIALOG_PERSISTSIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point getInitialSize() {
|
||||
Point size = super.getInitialSize();
|
||||
/*
|
||||
* If manual mode is selected fileGroup is missing and not accounted in
|
||||
* the size of the dialog shell. Add its height here manually if dialog
|
||||
* size was not persisted previously
|
||||
*/
|
||||
GridData fileGroupLayoutData = (GridData)fileGroup.getLayoutData();
|
||||
if (fileGroupLayoutData.exclude) {
|
||||
try {
|
||||
/*
|
||||
* Hack: check if dialog width/height was persisted. If
|
||||
* persisted then no need to calculate dialog size
|
||||
*/
|
||||
getDialogBoundsSettings().getInt("DIALOG_WIDTH");
|
||||
} catch (NumberFormatException e) {
|
||||
/*
|
||||
* Exception is thrown if dialog width/height cannot be read
|
||||
* from storage
|
||||
*/
|
||||
size.y += fileGroupLayoutData.heightHint;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private class EditorActionHandler extends AbstractHandler {
|
||||
|
||||
private String actionId;
|
||||
private int operationId;
|
||||
|
||||
public EditorActionHandler(String actionId, int operationId) {
|
||||
super();
|
||||
this.actionId = actionId;
|
||||
this.operationId = operationId;
|
||||
}
|
||||
|
||||
public String getActionId() {
|
||||
return actionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(ExecutionEvent arg0) throws ExecutionException {
|
||||
ProjectionViewer manualYamlViewer = model.getManualYamlEditor().getViewer();
|
||||
ProjectionViewer fileYamlViewer = model.getFileYamlEditor().getViewer();
|
||||
if (manualYamlViewer.isEditable() && manualYamlViewer.getControl().isVisible()
|
||||
&& manualYamlViewer.getTextWidget().isFocusControl()) {
|
||||
manualYamlViewer.doOperation(operationId);
|
||||
} else if (fileYamlViewer.isEditable() && fileYamlViewer.getControl().isVisible()
|
||||
&& fileYamlViewer.getTextWidget().isFocusControl()) {
|
||||
fileYamlViewer.doOperation(operationId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IFile findManifestYamlFile(IProject project) {
|
||||
if (project == null) {
|
||||
return null;
|
||||
}
|
||||
IFile file = project.getFile("manifest.yml");
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
IFile yamlFile = null;
|
||||
try {
|
||||
for (IResource r : project.members()) {
|
||||
if (r instanceof IFile) {
|
||||
file = (IFile) r;
|
||||
if (MANIFEST_YAML_FILE_FILTER.select(null, project, file)) {
|
||||
return file;
|
||||
} else if (YAML_FILE_FILTER.select(null, project, file)) {
|
||||
yamlFile = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
// ignore
|
||||
}
|
||||
return yamlFile;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,973 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.boot.dash.cf.dialogs;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.jdt.internal.ui.JavaPlugin;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.text.Document;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationModelEvent;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelListener;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IPropertyListener;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextViewerConfiguration;
|
||||
import org.eclipse.ui.part.FileEditorInput;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFApplication;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.AppNameAnnotation;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.AppNameAnnotationModel;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.AppNameAnnotationSupport;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.ApplicationManifestHandler;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.CloudApplicationDeploymentProperties;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.deployment.CloudData;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
|
||||
import org.springframework.ide.eclipse.boot.launch.properties.EmbeddedEditor;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.AbstractDisposable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.Validator;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.Log;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class DeploymentPropertiesDialogModel extends AbstractDisposable {
|
||||
|
||||
public static final String LSP_ERROR_ANNOTATION_TYPE = "org.eclipse.ui.workbench.texteditor.error";
|
||||
|
||||
public static final String DUMMY_FILE_MANIFEST_YML = ".file-manifest.yml";
|
||||
public static final String DUMMY_MANUAL_MANIFEST_YML = ".manual-manifest.yml";
|
||||
public static final String UNKNOWN_DEPLOYMENT_MANIFEST_TYPE_MUST_BE_EITHER_FILE_OR_MANUAL = "Unknown deployment manifest type. Must be either 'File' or 'Manual'.";
|
||||
public static final String NO_SUPPORT_TO_DETERMINE_APP_NAMES = "Support for determining application names is unavailable";
|
||||
public static final String MANIFEST_DOES_NOT_CONTAIN_DEPLOYMENT_PROPERTIES_FOR_APPLICATION_WITH_NAME = "Manifest does not contain deployment properties for application with name ''{0}''.";
|
||||
public static final String APPLICATION_NAME_NOT_SELECTED = "Application name not selected";
|
||||
public static final String MANIFEST_DOES_NOT_HAVE_ANY_APPLICATION_DEFINED = "Manifest does not have any application defined.";
|
||||
public static final String ENTER_DEPLOYMENT_MANIFEST_YAML_MANUALLY = "Enter deployment manifest YAML manually.";
|
||||
public static final String CURRENT_GENERATED_DEPLOYMENT_MANIFEST = "Current generated deployment manifest.";
|
||||
public static final String CHOOSE_AN_EXISTING_DEPLOYMENT_MANIFEST_YAML_FILE_FROM_THE_LOCAL_FILE_SYSTEM = "Choose an existing deployment manifest YAML file from the local file system.";
|
||||
public static final String DEPLOYMENT_MANIFEST_FILE_NOT_SELECTED = "Deployment manifest file not selected.";
|
||||
public static final String MANIFEST_YAML_ERRORS = "Deployment manifest YAML has errors.";
|
||||
|
||||
public static enum ManifestType {
|
||||
FILE,
|
||||
MANUAL
|
||||
}
|
||||
|
||||
private UserInteractions ui;
|
||||
|
||||
private abstract class AbstractSubModel extends AbstractDisposable {
|
||||
|
||||
EmbeddedEditor editor;
|
||||
|
||||
AppNameAnnotationSupport appNameAnnotationSupport;
|
||||
|
||||
final LiveVariable<Boolean> editorControlCreated;
|
||||
|
||||
final LiveVariable<IResource> selectedFile;
|
||||
|
||||
final LiveExpression<FileEditorInput> editorInput;
|
||||
|
||||
LiveExpression<AppNameAnnotationModel> appNameAnnotationModel;
|
||||
|
||||
LiveExpression<IAnnotationModel> resourceAnnotationModel;
|
||||
|
||||
LiveExpression<List<String>> applicationNames;
|
||||
|
||||
LiveExpression<Boolean> errorsInYaml;
|
||||
|
||||
LiveExpression<String> selectedAppName;
|
||||
|
||||
/**
|
||||
* When dialog closed and viewer disposed live expression would still keep the document which will be used to detrmine DeploymentProperties
|
||||
*/
|
||||
final LiveExpression<IDocument> document;
|
||||
|
||||
protected IFile getFile() {
|
||||
IResource r = selectedFile.getValue();
|
||||
return r instanceof IFile ? (IFile) r : null;
|
||||
}
|
||||
|
||||
protected void saveOrDiscardIfNeeded() {
|
||||
FileEditorInput input = editorInput.getValue();
|
||||
if (input != null) {
|
||||
saveOrDiscardIfNeeded(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveOrDiscardIfNeeded(FileEditorInput file) {
|
||||
if (editor.isDirty()) {
|
||||
if (ui.confirmOperation("Changes Detected", "Manifest file '" + file.getFile().getFullPath().toOSString()
|
||||
+ "' has been changed. Do you want to save changes or discard them?", new String[] {"Save", "Don't Save"}, 0) == 0) {
|
||||
editor.doSave(new NullProgressMonitor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract String getManifestContents();
|
||||
|
||||
/**
|
||||
* Return manifest from which contents are takes as an {@link IFile}
|
||||
* Return null if manifest content doesn't come from a file
|
||||
* @return
|
||||
*/
|
||||
abstract IFile getManifest();
|
||||
|
||||
CloudApplicationDeploymentProperties getDeploymentProperties() throws Exception {
|
||||
CloudApplicationDeploymentProperties deploymentProperties = toDeploymentProperties(cloudData,
|
||||
getManifestContents(), project,
|
||||
deployedApp == null ? selectedAppName.getValue() : getDeployedAppName());
|
||||
if (deploymentProperties != null) {
|
||||
deploymentProperties.setManifestFile(getManifest());
|
||||
}
|
||||
return deploymentProperties;
|
||||
}
|
||||
|
||||
protected AbstractSubModel(String fixedAppName) {
|
||||
IPreferenceStore preferenceStore = JavaPlugin.getDefault().getCombinedPreferenceStore();
|
||||
this.editor = new EmbeddedEditor(editor -> new ExtensionBasedTextViewerConfiguration(editor, preferenceStore), preferenceStore, false, true);
|
||||
|
||||
editorControlCreated = new LiveVariable<>(false);
|
||||
|
||||
selectedFile = new LiveVariable<>();
|
||||
|
||||
editorControlCreated.addListener((exp, value) -> {
|
||||
if (appNameAnnotationSupport == null && value != null && value.booleanValue()) {
|
||||
appNameAnnotationSupport = new AppNameAnnotationSupport(editor.getViewer(),
|
||||
editor.getAnnotationAccess(), editor.getSharedColors(), fixedAppName);
|
||||
}
|
||||
});
|
||||
|
||||
editorInput = new LiveExpression<FileEditorInput>() {
|
||||
|
||||
{
|
||||
dependsOn(selectedFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileEditorInput compute() {
|
||||
if (editor != null) {
|
||||
IFile file = getFile();
|
||||
FileEditorInput currentInput = getValue();
|
||||
boolean changed = currentInput == null || !currentInput.getFile().equals(file);
|
||||
if (changed) {
|
||||
if (currentInput != null) {
|
||||
saveOrDiscardIfNeeded(currentInput);
|
||||
}
|
||||
try {
|
||||
if (file != null) {
|
||||
FileEditorInput input = new FileEditorInput(file);
|
||||
editor.setInput(input);
|
||||
return input;
|
||||
} else {
|
||||
editor.setInput(null);
|
||||
return null;
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
appNameAnnotationModel = new LiveExpression<AppNameAnnotationModel>() {
|
||||
{
|
||||
dependsOn(editorControlCreated);
|
||||
dependsOn(editorInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppNameAnnotationModel compute() {
|
||||
if (editor != null && editor.getViewer() != null) {
|
||||
return AppNameAnnotationSupport.getAppNameAnnotationModel(editor.getViewer());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
resourceAnnotationModel = new LiveExpression<IAnnotationModel>() {
|
||||
|
||||
{
|
||||
dependsOn(editorControlCreated);
|
||||
dependsOn(editorInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IAnnotationModel compute() {
|
||||
if (editor != null && editor.getViewer() != null) {
|
||||
return editor.getViewer().getAnnotationModel();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
applicationNames = new LiveExpression<List<String>>() {
|
||||
|
||||
private AppNameAnnotationModel attachedTo = null;
|
||||
private AnnotationModelListener listener = new AnnotationModelListener() {
|
||||
@Override
|
||||
public void modelChanged(AnnotationModelEvent event) {
|
||||
refresh();
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
dependsOn(appNameAnnotationModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> compute() {
|
||||
AppNameAnnotationModel annotationModel = appNameAnnotationModel.getValue();
|
||||
if (annotationModel != null) {
|
||||
attachListener(annotationModel);
|
||||
List<String> applicationNames = new ArrayList<>();
|
||||
for (Iterator<Annotation> itr = annotationModel.getAnnotationIterator(); itr.hasNext();) {
|
||||
Annotation next = itr.next();
|
||||
if (next instanceof AppNameAnnotation) {
|
||||
AppNameAnnotation a = (AppNameAnnotation) next;
|
||||
applicationNames.add(a.getText());
|
||||
}
|
||||
}
|
||||
return applicationNames;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
synchronized private void attachListener(AppNameAnnotationModel annotationModel) {
|
||||
if (attachedTo == annotationModel) {
|
||||
return;
|
||||
}
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAnnotationModelListener(listener);
|
||||
}
|
||||
if (annotationModel != null) {
|
||||
annotationModel.addAnnotationModelListener(listener);
|
||||
}
|
||||
attachedTo = annotationModel;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
errorsInYaml = new LiveExpression<Boolean>() {
|
||||
|
||||
private IAnnotationModel attachedTo = null;
|
||||
private AnnotationModelListener listener = new AnnotationModelListener() {
|
||||
@Override
|
||||
public void modelChanged(AnnotationModelEvent event) {
|
||||
refresh();
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
dependsOn(resourceAnnotationModel);
|
||||
}
|
||||
|
||||
{
|
||||
onDispose((d) -> {
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAnnotationModelListener(listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean compute() {
|
||||
IAnnotationModel annotationModel = resourceAnnotationModel.getValue();
|
||||
if (annotationModel != null) {
|
||||
attachListener(annotationModel);
|
||||
for (Iterator<Annotation> itr = annotationModel.getAnnotationIterator(); itr.hasNext();) {
|
||||
Annotation next = itr.next();
|
||||
if (LSP_ERROR_ANNOTATION_TYPE.equals(next.getType())) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
synchronized private void attachListener(IAnnotationModel annotationModel) {
|
||||
if (attachedTo == annotationModel) {
|
||||
return;
|
||||
}
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAnnotationModelListener(listener);
|
||||
}
|
||||
if (annotationModel != null) {
|
||||
annotationModel.addAnnotationModelListener(listener);
|
||||
}
|
||||
attachedTo = annotationModel;
|
||||
}
|
||||
};
|
||||
|
||||
selectedAppName = new LiveExpression<String>() {
|
||||
|
||||
private AppNameAnnotationModel attachedTo = null;
|
||||
private AnnotationModelListener listener = new AnnotationModelListener() {
|
||||
@Override
|
||||
public void modelChanged(AnnotationModelEvent event) {
|
||||
refresh();
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
dependsOn(appNameAnnotationModel);
|
||||
}
|
||||
|
||||
{
|
||||
onDispose((d) -> {
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAnnotationModelListener(listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String compute() {
|
||||
AppNameAnnotationModel annotationModel = appNameAnnotationModel.getValue();
|
||||
if (annotationModel != null) {
|
||||
attachListener(annotationModel);
|
||||
AppNameAnnotation a = annotationModel.getSelectedAppAnnotation();
|
||||
if (a != null) {
|
||||
return a.getText();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized private void attachListener(AppNameAnnotationModel annotationModel) {
|
||||
if (attachedTo == annotationModel) {
|
||||
return;
|
||||
}
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAnnotationModelListener(listener);
|
||||
}
|
||||
if (annotationModel != null) {
|
||||
annotationModel.addAnnotationModelListener(listener);
|
||||
}
|
||||
attachedTo = annotationModel;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
document = new LiveExpression<IDocument>(new Document("")) {
|
||||
{
|
||||
dependsOn(editorInput);
|
||||
dependsOn(editorControlCreated);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDocument compute() {
|
||||
IDocument doc = editor == null || editor.getViewer() == null ? null : editor.getViewer().getDocument();
|
||||
return doc;
|
||||
}
|
||||
};
|
||||
|
||||
onDispose((d) -> {
|
||||
appNameAnnotationSupport.dispose();
|
||||
editorControlCreated.dispose();
|
||||
editorInput.dispose();
|
||||
applicationNames.dispose();
|
||||
appNameAnnotationModel.dispose();
|
||||
errorsInYaml.dispose();
|
||||
resourceAnnotationModel.dispose();
|
||||
selectedAppName.dispose();
|
||||
document.dispose();
|
||||
editor.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class FileDeploymentPropertiesDialogModel extends AbstractSubModel {
|
||||
|
||||
final private LiveExpression<String> fileLabel = new LiveExpression<String>() {
|
||||
{
|
||||
dependsOn(editorInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String compute() {
|
||||
FileEditorInput input = editorInput.getValue();
|
||||
if (input != null) {
|
||||
return editorInput.getValue().getFile().getFullPath().toOSString() + (editor.isDirty() ? "*" : "");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final IPropertyListener editorListener = (Object source, int propId) -> {
|
||||
if (propId == IEditorPart.PROP_DIRTY) {
|
||||
fileLabel.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
Validator validator = new Validator() {
|
||||
|
||||
{
|
||||
dependsOn(editorInput);
|
||||
dependsOn(appNameAnnotationModel);
|
||||
dependsOn(errorsInYaml);
|
||||
dependsOn(applicationNames);
|
||||
dependsOn(selectedAppName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
ValidationResult result = ValidationResult.OK;
|
||||
|
||||
if (editorInput.getValue() == null) {
|
||||
result = ValidationResult.error(DEPLOYMENT_MANIFEST_FILE_NOT_SELECTED);
|
||||
}
|
||||
|
||||
if (result.isOk()) {
|
||||
AppNameAnnotationModel appNamesModel = appNameAnnotationModel.getValue();
|
||||
if (appNamesModel == null) {
|
||||
result = ValidationResult.error(NO_SUPPORT_TO_DETERMINE_APP_NAMES);
|
||||
}
|
||||
if (result.isOk()) {
|
||||
String appName = getDeployedAppName();
|
||||
if (applicationNames.getValue().isEmpty()) {
|
||||
result = ValidationResult.error(MANIFEST_DOES_NOT_HAVE_ANY_APPLICATION_DEFINED);
|
||||
} else {
|
||||
if (errorsInYaml.getValue().booleanValue()) {
|
||||
result = ValidationResult.error(MANIFEST_YAML_ERRORS);
|
||||
} else {
|
||||
String selectedAnnotation = selectedAppName.getValue();
|
||||
if (appName == null) {
|
||||
if (selectedAnnotation == null) {
|
||||
result = ValidationResult.error(APPLICATION_NAME_NOT_SELECTED);
|
||||
}
|
||||
} else {
|
||||
if (selectedAnnotation == null || !appName.equals(selectedAnnotation)) {
|
||||
result = ValidationResult.error(MessageFormat.format(
|
||||
MANIFEST_DOES_NOT_CONTAIN_DEPLOYMENT_PROPERTIES_FOR_APPLICATION_WITH_NAME,
|
||||
appName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isOk()) {
|
||||
result = ValidationResult.info(CHOOSE_AN_EXISTING_DEPLOYMENT_MANIFEST_YAML_FILE_FROM_THE_LOCAL_FILE_SYSTEM);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private IFile tempFile;
|
||||
|
||||
{
|
||||
onDispose((d) -> {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
try {
|
||||
tempFile.delete(true, new NullProgressMonitor());
|
||||
} catch (CoreException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
editor.removePropertyListener(editorListener);
|
||||
validator.dispose();
|
||||
fileLabel.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
FileDeploymentPropertiesDialogModel(String fixedAppName) {
|
||||
super(fixedAppName);
|
||||
editor.addPropertyListener(editorListener);
|
||||
}
|
||||
|
||||
public void init(IFile tempFile) {
|
||||
this.tempFile = tempFile;
|
||||
if (getManifest() == null) {
|
||||
// No manifest file? Generate dumb empty manifest YAML to get proper Manifest LS
|
||||
// based reconciler, CA etc
|
||||
try {
|
||||
generateTempManifestFile(tempFile, "");
|
||||
editor.init(null, new FileEditorInput(tempFile));
|
||||
} catch (CoreException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IAnnotationModel getAnnotationModel() {
|
||||
return editor.getViewer().getAnnotationModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManifestContents() {
|
||||
return document.getValue().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
IFile getManifest() {
|
||||
return getFile();
|
||||
}
|
||||
|
||||
void reopenSameFile() {
|
||||
document.refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ManualDeploymentPropertiesDialogModel extends AbstractSubModel {
|
||||
|
||||
private IFile tempFile;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
Validator validator = new Validator() {
|
||||
|
||||
{
|
||||
dependsOn(appNameAnnotationModel);
|
||||
dependsOn(errorsInYaml);
|
||||
dependsOn(applicationNames);
|
||||
dependsOn(selectedAppName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
ValidationResult result = ValidationResult.OK;
|
||||
|
||||
AppNameAnnotationModel appNamesModel = appNameAnnotationModel.getValue();
|
||||
if (appNamesModel == null) {
|
||||
result = ValidationResult.error(NO_SUPPORT_TO_DETERMINE_APP_NAMES);
|
||||
}
|
||||
if (result.isOk()) {
|
||||
String appName = getDeployedAppName();
|
||||
if (applicationNames.getValue().isEmpty()) {
|
||||
result = ValidationResult.error(MANIFEST_DOES_NOT_HAVE_ANY_APPLICATION_DEFINED);
|
||||
} else {
|
||||
if (errorsInYaml.getValue().booleanValue()) {
|
||||
result = ValidationResult.error(MANIFEST_YAML_ERRORS);
|
||||
} else {
|
||||
String selectedAnnotation = selectedAppName.getValue();
|
||||
if (appName == null) {
|
||||
if (selectedAnnotation == null) {
|
||||
result = ValidationResult.error(APPLICATION_NAME_NOT_SELECTED);
|
||||
}
|
||||
} else {
|
||||
if (selectedAnnotation == null || !appName.equals(selectedAnnotation)) {
|
||||
result = ValidationResult.error(MessageFormat.format(
|
||||
MANIFEST_DOES_NOT_CONTAIN_DEPLOYMENT_PROPERTIES_FOR_APPLICATION_WITH_NAME,
|
||||
appName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isOk()) {
|
||||
result = ValidationResult.info(readOnly ? CURRENT_GENERATED_DEPLOYMENT_MANIFEST : ENTER_DEPLOYMENT_MANIFEST_YAML_MANUALLY);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
onDispose((d) -> {
|
||||
validator.dispose();
|
||||
try {
|
||||
if (tempFile != null) {
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete(true, new NullProgressMonitor());
|
||||
}
|
||||
tempFile = null;
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
ManualDeploymentPropertiesDialogModel(String fixedAppName, boolean readOnly) {
|
||||
super(fixedAppName);
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public void init(IFile tempFile) {
|
||||
this.tempFile = tempFile;
|
||||
try {
|
||||
generateTempManifestFile(tempFile, generateDefaultContent());
|
||||
} catch (CoreException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
editor.init(null, new FileEditorInput(tempFile));
|
||||
selectedFile.setValue(tempFile);
|
||||
} catch (PartInitException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(String s) {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("The model is read-only!");
|
||||
}
|
||||
IDocument doc = document.getValue();
|
||||
if (doc != null) {
|
||||
doc.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
IDocument doc = document.getValue();
|
||||
return doc == null ? null : doc.get();
|
||||
}
|
||||
|
||||
public IAnnotationModel getAnnotationModel() {
|
||||
return editor.getViewer().getAnnotationModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManifestContents() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
IFile getManifest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract class AnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
|
||||
|
||||
@Override
|
||||
public void modelChanged(IAnnotationModel model) {
|
||||
// Leave empty. AnnotationModelEvent method is the one that will be called
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public void modelChanged(AnnotationModelEvent event);
|
||||
|
||||
}
|
||||
|
||||
|
||||
final public LiveVariable<ManifestType> type = new LiveVariable<>();
|
||||
final public LiveVariable<Boolean> enableJmxSshTunnel = new LiveVariable<>();
|
||||
|
||||
final private CFApplication deployedApp;
|
||||
|
||||
final private CloudData cloudData;
|
||||
|
||||
final IProject project;
|
||||
|
||||
final private FileDeploymentPropertiesDialogModel fileModel;
|
||||
|
||||
final private ManualDeploymentPropertiesDialogModel manualModel;
|
||||
|
||||
private boolean isCancelled = false;
|
||||
|
||||
final private Validator validator;
|
||||
|
||||
final public boolean supportsSsh;
|
||||
|
||||
public DeploymentPropertiesDialogModel(UserInteractions ui, CloudData cloudData, IProject project, CFApplication deployedApp, boolean supportsSsh) {
|
||||
super();
|
||||
this.supportsSsh = supportsSsh;
|
||||
this.ui = ui;
|
||||
this.deployedApp = deployedApp;
|
||||
this.cloudData = cloudData;
|
||||
this.project = project;
|
||||
this.manualModel = new ManualDeploymentPropertiesDialogModel(getDeployedAppName(), deployedApp != null);
|
||||
this.fileModel = new FileDeploymentPropertiesDialogModel(getDeployedAppName());
|
||||
|
||||
this.validator = new Validator() {
|
||||
|
||||
{
|
||||
dependsOn(type);
|
||||
dependsOn(fileModel.validator);
|
||||
dependsOn(manualModel.validator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValidationResult compute() {
|
||||
if (isFileManifestType()) {
|
||||
return fileModel.validator.getValue();
|
||||
} else if (isManualManifestType()) {
|
||||
return manualModel.validator.getValue();
|
||||
} else {
|
||||
return ValidationResult.error(UNKNOWN_DEPLOYMENT_MANIFEST_TYPE_MUST_BE_EITHER_FILE_OR_MANUAL);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
onDispose((d) -> {
|
||||
fileModel.dispose();
|
||||
manualModel.dispose();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void initFileModel() {
|
||||
fileModel.init(project.getFolder(".settings").getFile(DUMMY_FILE_MANIFEST_YML));
|
||||
}
|
||||
|
||||
public void initManualModel() {
|
||||
manualModel.init(project.getFolder(".settings").getFile(DUMMY_MANUAL_MANIFEST_YML));
|
||||
}
|
||||
|
||||
public CloudApplicationDeploymentProperties getDeploymentProperties() throws Exception {
|
||||
if (isCancelled) {
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
if (type.getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
CloudApplicationDeploymentProperties props = null;
|
||||
switch (type.getValue()) {
|
||||
case FILE:
|
||||
props = fileModel.getDeploymentProperties();
|
||||
break;
|
||||
case MANUAL:
|
||||
props = manualModel.getDeploymentProperties();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if (props!=null) {
|
||||
Boolean enableJmx = enableJmxSshTunnel.getValue();
|
||||
props.setEnableJmxSshTunnel(enableJmx!=null && enableJmx);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
public void cancelPressed() {
|
||||
fileModel.saveOrDiscardIfNeeded();
|
||||
isCancelled = true;
|
||||
// try {
|
||||
// fileModel.editor.setInput(null);
|
||||
// manualModel.editor.setInput(null);
|
||||
// } catch (CoreException e) {
|
||||
// Log.log(e);
|
||||
// }
|
||||
}
|
||||
|
||||
public boolean okPressed() {
|
||||
fileModel.saveOrDiscardIfNeeded();
|
||||
isCancelled = false;
|
||||
try {
|
||||
CloudApplicationDeploymentProperties deploymentProperties = getDeploymentProperties();
|
||||
// fileModel.editor.setInput(null);
|
||||
// manualModel.editor.setInput(null);
|
||||
return deploymentProperties != null;
|
||||
} catch (Exception e) {
|
||||
fileModel.reopenSameFile();
|
||||
ui.errorPopup("Invalid YAML content", ExceptionUtil.getMessage(e));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedManifest(IResource manifest) {
|
||||
fileModel.selectedFile.setValue(manifest);
|
||||
}
|
||||
|
||||
public void setManualManifest(String manifestText) {
|
||||
manualModel.setText(manifestText);
|
||||
}
|
||||
|
||||
public void setManifestType(ManifestType type) {
|
||||
this.type.setValue(type);
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return project.getName();
|
||||
}
|
||||
|
||||
public IProject getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public boolean isFileManifestType() {
|
||||
return type.getValue() == ManifestType.FILE;
|
||||
}
|
||||
|
||||
public boolean isManualManifestType() {
|
||||
return type.getValue() == ManifestType.MANUAL;
|
||||
}
|
||||
|
||||
public IResource getSelectedManifest() {
|
||||
return fileModel.selectedFile.getValue();
|
||||
}
|
||||
|
||||
public String getDeployedAppName() {
|
||||
return deployedApp == null ? null : deployedApp.getName();
|
||||
}
|
||||
|
||||
public EmbeddedEditor getFileYamlEditor() {
|
||||
return fileModel.editor;
|
||||
}
|
||||
|
||||
public EmbeddedEditor getManualYamlEditor() {
|
||||
return manualModel.editor;
|
||||
}
|
||||
|
||||
public IDocument getManualDocument() {
|
||||
return manualModel.document.getValue();
|
||||
}
|
||||
|
||||
public boolean isManualManifestReadOnly() {
|
||||
return deployedApp!=null;
|
||||
}
|
||||
|
||||
public IDocument getFileDocument() {
|
||||
return fileModel.document.getValue();
|
||||
}
|
||||
|
||||
public LiveExpression<FileEditorInput> getFileEditorInput() {
|
||||
return fileModel.editorInput;
|
||||
}
|
||||
|
||||
public LiveExpression<String> getFileLabel() {
|
||||
return fileModel.fileLabel;
|
||||
}
|
||||
|
||||
private CFApplication getDeployedApp() {
|
||||
return deployedApp;
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
public Validator getValidator() {
|
||||
return validator;
|
||||
}
|
||||
|
||||
public LiveExpression<AppNameAnnotationModel> getManualAppNameAnnotationModel() {
|
||||
return manualModel.appNameAnnotationModel;
|
||||
}
|
||||
|
||||
public LiveExpression<AppNameAnnotationModel> getFileAppNameAnnotationModel() {
|
||||
return fileModel.appNameAnnotationModel;
|
||||
}
|
||||
|
||||
public void fileYamlEditorControlCreated() {
|
||||
fileModel.editorControlCreated.setValue(true);
|
||||
}
|
||||
|
||||
public void manualYamlEditorControlCreated() {
|
||||
manualModel.editorControlCreated.setValue(true);
|
||||
}
|
||||
|
||||
public IAnnotationModel getManualResourceAnnotationModel() {
|
||||
return manualModel.resourceAnnotationModel.getValue();
|
||||
}
|
||||
|
||||
public IAnnotationModel getFileResourceAnnotationModel() {
|
||||
return fileModel.resourceAnnotationModel.getValue();
|
||||
}
|
||||
|
||||
public String getFileSelectedAppName() {
|
||||
return fileModel.selectedAppName.getValue();
|
||||
}
|
||||
|
||||
public String getManualSelectedAppName() {
|
||||
return manualModel.selectedAppName.getValue();
|
||||
}
|
||||
|
||||
private String generateDefaultContent() {
|
||||
CloudApplicationDeploymentProperties props = CloudApplicationDeploymentProperties.getFor(project, cloudData,
|
||||
getDeployedApp());
|
||||
Map<Object, Object> yaml = ApplicationManifestHandler.toYaml(props, cloudData);
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setExplicitStart(true);
|
||||
options.setCanonical(false);
|
||||
options.setPrettyFlow(true);
|
||||
options.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||
return new Yaml(new SafeConstructor(), new Representer(options), options).dump(yaml);
|
||||
}
|
||||
|
||||
|
||||
private static IFile generateTempManifestFile(IFile manifestFile, String content) throws CoreException {
|
||||
if (manifestFile.exists()) {
|
||||
manifestFile.setContents(new ByteArrayInputStream(content.getBytes()), true, false, new NullProgressMonitor());
|
||||
} else {
|
||||
if (!manifestFile.getParent().exists()) {
|
||||
((IFolder)manifestFile.getParent()).create(true, true, new NullProgressMonitor());
|
||||
}
|
||||
manifestFile.create(new ByteArrayInputStream(content.getBytes()), true, new NullProgressMonitor());
|
||||
}
|
||||
return manifestFile;
|
||||
}
|
||||
|
||||
public static CloudApplicationDeploymentProperties toDeploymentProperties(CloudData cloudData, String yaml, IProject project, String applicationName) throws Exception {
|
||||
List<CloudApplicationDeploymentProperties> propsList = new ApplicationManifestHandler(project, cloudData, null) {
|
||||
@Override
|
||||
protected InputStream getInputStream() throws Exception {
|
||||
return new ByteArrayInputStream(yaml.getBytes());
|
||||
}
|
||||
}.load(new NullProgressMonitor());
|
||||
/*
|
||||
* If "Select Manifest..." action is invoked appName is not null,
|
||||
* but we should allow for any manifest file selected for now. Hence
|
||||
* set the applicationName var to null in that case
|
||||
*/
|
||||
CloudApplicationDeploymentProperties deploymentProperties = null;
|
||||
if (applicationName == null) {
|
||||
deploymentProperties = propsList.get(0);
|
||||
} else {
|
||||
for (CloudApplicationDeploymentProperties p : propsList) {
|
||||
if (applicationName.equals(p.getAppName())) {
|
||||
deploymentProperties = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return deploymentProperties;
|
||||
}
|
||||
|
||||
public CloudApplicationDeploymentProperties getDeploymentProperties(String yaml, String appName) throws Exception {
|
||||
if (yaml == null) {
|
||||
yaml = generateDefaultContent();
|
||||
}
|
||||
return toDeploymentProperties(cloudData, yaml, project, appName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.dialogs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFOrganization;
|
||||
import org.springframework.ide.eclipse.boot.dash.cf.client.CFSpace;
|
||||
|
||||
/**
|
||||
* Hierarchical representation of existing orgs and spaces in a Cloud Foundry
|
||||
* target.
|
||||
*
|
||||
*/
|
||||
public class OrgsAndSpaces {
|
||||
|
||||
private final List<CFSpace> originalSpaces;
|
||||
private Map<String, List<CFSpace>> orgIDtoSpaces;
|
||||
private Map<String,CFOrganization> orgIDtoOrg;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param spaces
|
||||
* a flat list of all spaces for a given set of credentials and
|
||||
* server URL. Should not be empty or null.
|
||||
* @throws CoreException
|
||||
* if given cloud server does not support orgs and spaces
|
||||
*/
|
||||
public OrgsAndSpaces(List<CFSpace> spaces) {
|
||||
this.originalSpaces = spaces;
|
||||
setValues();
|
||||
}
|
||||
|
||||
public CFSpace getSpace(String orgName, String spaceName) {
|
||||
List<CFSpace> oSpaces = orgIDtoSpaces.get(orgName);
|
||||
if (oSpaces != null) {
|
||||
for (CFSpace clSpace : oSpaces) {
|
||||
if (clSpace.getName().equals(spaceName)) {
|
||||
return clSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<CFOrganization> getOrgs() {
|
||||
|
||||
Collection<CFOrganization> orgList = orgIDtoOrg.values();
|
||||
return new ArrayList<CFOrganization>(orgList);
|
||||
}
|
||||
|
||||
protected void setValues() {
|
||||
orgIDtoSpaces = new HashMap<String, List<CFSpace>>();
|
||||
orgIDtoOrg = new HashMap<String, CFOrganization>();
|
||||
|
||||
for (CFSpace clSpace : originalSpaces) {
|
||||
CFOrganization org = clSpace.getOrganization();
|
||||
List<CFSpace> spaces = orgIDtoSpaces.get(org.getName());
|
||||
if (spaces == null) {
|
||||
spaces = new ArrayList<CFSpace>();
|
||||
orgIDtoSpaces.put(org.getName(), spaces);
|
||||
orgIDtoOrg.put(org.getName(), org);
|
||||
}
|
||||
|
||||
spaces.add(clSpace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param orgName
|
||||
* @return
|
||||
*/
|
||||
public List<CFSpace> getOrgSpaces(String orgName) {
|
||||
return orgIDtoSpaces.get(orgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all spaces available for the given account. Never null, although
|
||||
* may be empty if no spaces are resolved.
|
||||
*/
|
||||
public List<CFSpace> getAllSpaces() {
|
||||
return originalSpaces != null ? new ArrayList<CFSpace>(originalSpaces) : new ArrayList<CFSpace>(0);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user