diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFClientParams.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFClientParams.java index 898475647..133e1accf 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFClientParams.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFClientParams.java @@ -53,6 +53,11 @@ public class CFClientParams { this.orgName = orgName; this.spaceName = spaceName; } + + public CFClientParams(String apiUrl, String username, CFCredentials credentials, boolean skipSslValidation) { + this(apiUrl, username, credentials, null /* no org */, + null /* no space */, skipSslValidation); + } public CFCredentials getCredentials() { return credentials; diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java index c6fb4158b..37dd89047 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java @@ -11,12 +11,17 @@ package org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientRequests; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + /** * * Wrapper around a {@link ClientRequests} that may contain cached information @@ -32,28 +37,50 @@ public class CFTarget { /* * Cached information */ - private List buildpacks; - private final static Logger logger = Logger.getLogger(CFTarget.class.getName()); + private final LoadingCache> buildpacksCache; + private final LoadingCache> servicesCache; - public CFTarget(CFClientParams params, ClientRequests requests, String targetName) { + public CFTarget(String targetName, CFClientParams params, ClientRequests requests) { this.params = params; this.requests = requests; this.targetName = targetName; + CacheLoader> servicesLoader = new CacheLoader>() { + + @Override + public List load(String key) throws Exception { + /* + * Ignore the key. Not used. + */ + return requests.getServices(); + } + }; + this.servicesCache = CacheBuilder.newBuilder() + .expireAfterAccess(CFTargetCache.EXPIRATION_20_SECS, TimeUnit.SECONDS).build(servicesLoader); + + CacheLoader> buildpacksLoader = new CacheLoader>() { + + @Override + public List load(String key) throws Exception { + /* + * Ignore the key. Not used. + */ + return requests.getBuildpacks(); + } + }; + this.buildpacksCache = CacheBuilder.newBuilder() + .expireAfterAccess(CFTargetCache.EXPIRATION_1_HOUR, TimeUnit.HOURS).build(buildpacksLoader); } public CFClientParams getParams() { return params; } - public List getBuildpacks() { - if (buildpacks == null) { - try { - buildpacks = getClientRequests().getBuildpacks(); - } catch (Exception e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } - } - return buildpacks; + public List getBuildpacks() throws ExecutionException { + return this.buildpacksCache.get(getName()); + } + + public List getServices() throws ExecutionException { + return this.servicesCache.get(getName()); } public ClientRequests getClientRequests() { diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetCache.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetCache.java new file mode 100644 index 000000000..c6ecd933a --- /dev/null +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetCache.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientTimeouts; +import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.CloudFoundryClientFactory; +import org.springframework.ide.vscode.commons.util.Assert; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +public class CFTargetCache { + + private final ClientParamsProvider paramsProvider; + private final CloudFoundryClientFactory clientFactory; + private final ClientTimeouts timeouts; + private final LoadingCache cache; + + public static final long EXPIRATION_20_SECS = 20; + public static final long EXPIRATION_1_HOUR = 1; + + public CFTargetCache(ClientParamsProvider paramsProvider, CloudFoundryClientFactory clientFactory, + ClientTimeouts timeouts) { + Assert.isLegal(paramsProvider != null, + "A Cloud Foundry client parameters provider must be set when creating a target cache."); + this.paramsProvider = paramsProvider; + this.clientFactory = clientFactory; + this.timeouts = timeouts; + CacheLoader loader = new CacheLoader() { + + @Override + public CFTarget load(CFClientParams params) throws Exception { + return create(params); + } + + }; + cache = CacheBuilder.newBuilder().expireAfterAccess(EXPIRATION_1_HOUR, TimeUnit.HOURS).build(loader); + } + + /** + * @return non-null list of targets, or throws exception if no targets found + * @throws Exception if no targets found, or error in resolving targets + */ + public synchronized List getOrCreate() throws Exception { + + List allParams = paramsProvider.getParams(); + List targets = new ArrayList<>(); + if (allParams != null) { + for (CFClientParams params : allParams) { + CFTarget target = cache.get(params); + if (target != null) { + targets.add(target); + } + } + } + + if (targets.isEmpty()) { + throw new ExecutionException(new Error(paramsProvider.noParamsAvailableMessage())); + } + + return targets; + } + + protected CFTarget create(CFClientParams params) throws Exception { + return new CFTarget(getTargetName(params), params, clientFactory.getClient(params, timeouts)); + } + + protected static String getTargetName(CFClientParams params) { + return labelFromCfApi(params.getApiUrl()); + } + + protected static String labelFromCfApi(String cfApiUrl) { + if (cfApiUrl.startsWith("https://")) { + return cfApiUrl.substring("https://".length()); + } else if (cfApiUrl.startsWith("http://")) { + return cfApiUrl.substring("http://".length()); + } else { + return cfApiUrl; + } + } +} diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetsFactory.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetsFactory.java deleted file mode 100644 index e88e50cf3..000000000 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTargetsFactory.java +++ /dev/null @@ -1,72 +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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Pivotal, Inc. - initial API and implementation - *******************************************************************************/ -package org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientRequests; -import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientTimeouts; -import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.CloudFoundryClientFactory; - -/** - * Creates targets given a client parameters provider and a client factory. - * - */ -public class CFTargetsFactory { - - private final CloudFoundryClientFactory clientFactory; - private final ClientParamsProvider paramsProvider; - private final ClientTimeouts timeouts; - - public CFTargetsFactory(ClientParamsProvider paramsProvider, CloudFoundryClientFactory clientFactory, ClientTimeouts timeouts) { - this.clientFactory = clientFactory; - this.paramsProvider = paramsProvider; - this.timeouts = timeouts; - } - - /** - * - * @return up-to-date list of CF targets. - * @throws Exception - */ - public List getTargets() throws Exception { - List allParams = paramsProvider.getParams(); - List targets = new ArrayList<>(); - if (allParams != null) { - for (CFClientParams parameters : allParams) { - ClientRequests requests = clientFactory.getClient(parameters, timeouts); - if (requests != null) { - targets.add(new CFTarget(parameters, requests, getTargetName(parameters))); - } - } - } - return targets; - } - - public String noTargetsMessage() { - return paramsProvider.noParamsAvailableMessage(); - } - - protected String getTargetName(CFClientParams params) { - return labelFromCfApi(params.getApiUrl()); - } - - public static String labelFromCfApi(String cfApiUrl) { - if (cfApiUrl.startsWith("https://")) { - return cfApiUrl.substring("https://".length()); - } else if (cfApiUrl.startsWith("http://")) { - return cfApiUrl.substring("http://".length()); - } else { - return cfApiUrl; - } - } -} diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java index 3e3c3a29c..8e434c401 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Pivotal, Inc. + * 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 @@ -41,26 +41,18 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.CFStack; 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. + * 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 { - - - private static final Logger logger = Logger.getLogger(DefaultClientRequestsV2.class.getName()); + private static final Logger logger = Logger.getLogger(DefaultClientRequestsV2.class.getName()); public static CFBuildpack wrap(BuildpackResource rsrc) { String name = rsrc.getEntity().getName(); - return new CFBuildpack() { - @Override - public String getName() { - return name; - } - }; + return new CFBuildpackImpl(name); } public static CFApplicationDetail wrap(ApplicationDetail details, ApplicationExtras extras) { @@ -191,43 +183,8 @@ public class CFWrappingV2 { ); } - 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 CFServiceInstance wrap(ServiceInstance service) { + return new CFServiceInstanceImpl(service); } public static CFAppState wrapAppState(String s) { @@ -276,12 +233,154 @@ public class CFWrappingV2 { } public static CFBuildpack buildpack(String name) { - return new CFBuildpack() { - @Override - public String getName() { - return name; - } - }; + return new CFBuildpackImpl(name); + } + + public static class CFBuildpackImpl implements CFBuildpack { + + private final String name; + + public CFBuildpackImpl(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.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; + CFBuildpackImpl other = (CFBuildpackImpl) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + } + + public static class CFServiceInstanceImpl implements CFServiceInstance { + + private final String name; + private final String plan; + private final String dashboardUrl; + private final String service; + private final String description; + private final String documentationUrl; + + public CFServiceInstanceImpl(ServiceInstance serviceInstance) { + this.name = serviceInstance.getName(); + this.plan = serviceInstance.getPlan(); + this.dashboardUrl = serviceInstance.getDashboardUrl(); + this.service = serviceInstance.getType() == ServiceInstanceType.USER_PROVIDED ? "user-provided" + : serviceInstance.getService(); + this.description = serviceInstance.getDescription(); + this.documentationUrl = serviceInstance.getDocumentationUrl(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getPlan() { + return this.plan; + } + + @Override + public String getDashboardUrl() { + return this.dashboardUrl; + } + + @Override + public String getService() { + return this.service; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public String getDocumentationUrl() { + return this.documentationUrl; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((dashboardUrl == null) ? 0 : dashboardUrl.hashCode()); + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((documentationUrl == null) ? 0 : documentationUrl.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((plan == null) ? 0 : plan.hashCode()); + result = prime * result + ((service == null) ? 0 : service.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; + CFServiceInstanceImpl other = (CFServiceInstanceImpl) obj; + if (dashboardUrl == null) { + if (other.dashboardUrl != null) + return false; + } else if (!dashboardUrl.equals(other.dashboardUrl)) + return false; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (documentationUrl == null) { + if (other.documentationUrl != null) + return false; + } else if (!documentationUrl.equals(other.documentationUrl)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (plan == null) { + if (other.plan != null) + return false; + } else if (!plan.equals(other.plan)) + return false; + if (service == null) { + if (other.service != null) + return false; + } else if (!service.equals(other.service)) + return false; + return true; + } + + } } diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/ClientRequests.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/ClientRequests.java index 79d8f67dc..ff11b29ad 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/ClientRequests.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/ClientRequests.java @@ -29,6 +29,9 @@ import reactor.core.publisher.Mono; public interface ClientRequests { + List getBuildpacks() throws Exception; + List getServices() throws Exception; + // /** // * The actual Rest API version that cloud controller claims to be. // */ @@ -38,48 +41,47 @@ public interface ClientRequests { // * 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; - void logout(); - - List getApplicationsWithBasicInfo() throws Exception; - List getBuildpacks() throws Exception; - List getDomains() throws Exception; - List getServices() throws Exception; - List getSpaces() throws Exception; - List getStacks() throws Exception; - void restartApplication(String appName, CancelationToken token) throws Exception; - void stopApplication(String appName) throws Exception; - Flux getApplicationDetails(List appsToLookUp) throws Exception; - String getHealthCheck(UUID appGuid) throws Exception; - void setHealthCheck(UUID guid, String hcType) throws Exception; - boolean applicationExists(String appName) throws Exception; - - //Removed in V2 - //void createApplication(CloudApplicationDeploymentProperties deploymentProperties) throws Exception; - - //Added since v2: - void push(CFPushArguments args, CancelationToken cancelationToken) throws Exception; - Map getApplicationEnvironment(String appName) throws Exception; - Mono deleteServiceAsync(String serviceName); - - /** - * Gets current value of the client's refresh token. Note that the token is only set once it is known. - * Initially, if a client is created via password auth, then the refreshToken won't be known until - * some operation has been executed. - * - * @return Refresh token if it is already known, null otherwise. - */ - String getRefreshToken(); - Mono getUserName(); +// +// /** +// * 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; +// void logout(); +// List getDomains() throws Exception; +// +// List getApplicationsWithBasicInfo() throws Exception; +// +// List getSpaces() throws Exception; +// List getStacks() throws Exception; +// void restartApplication(String appName, CancelationToken token) throws Exception; +// void stopApplication(String appName) throws Exception; +// Flux getApplicationDetails(List appsToLookUp) throws Exception; +// String getHealthCheck(UUID appGuid) throws Exception; +// void setHealthCheck(UUID guid, String hcType) throws Exception; +// boolean applicationExists(String appName) throws Exception; +// +// //Removed in V2 +// //void createApplication(CloudApplicationDeploymentProperties deploymentProperties) throws Exception; +// +// //Added since v2: +// void push(CFPushArguments args, CancelationToken cancelationToken) throws Exception; +// Map getApplicationEnvironment(String appName) throws Exception; +// Mono deleteServiceAsync(String serviceName); +// +// /** +// * Gets current value of the client's refresh token. Note that the token is only set once it is known. +// * Initially, if a client is created via password auth, then the refreshToken won't be known until +// * some operation has been executed. +// * +// * @return Refresh token if it is already known, null otherwise. +// */ +// String getRefreshToken(); +// Mono getUserName(); } diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CloudFoundryClientCache.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CloudFoundryClientCache.java index c6ef40ef7..7e1d9c474 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CloudFoundryClientCache.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CloudFoundryClientCache.java @@ -26,6 +26,7 @@ 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.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFClientParams; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFCredentials; /** @@ -99,16 +100,16 @@ public class CloudFoundryClientCache { return null; } - public CFClientProvider(Params params) { + public CFClientProvider(CFClientParams params) { long sslTimeout = Long.getLong("sts.bootdash.cf.client.ssl.handshake.timeout", 60); //TODO: make a preference for this? Optional keepAlive = getBooleanSystemProp("http.keepAlive"); debug("cf client keepAlive = "+keepAlive); connection = DefaultConnectionContext.builder() - .proxyConfiguration(Optional.ofNullable(getProxy(params.host))) - .apiHost(params.host) + .proxyConfiguration(Optional.ofNullable(getProxy(params.getHost()))) + .apiHost(params.getHost()) .sslHandshakeTimeout(Duration.ofSeconds(sslTimeout)) .keepAlive(keepAlive) - .skipSslValidation(params.skipSsl) + .skipSslValidation(params.skipSslValidation()) .build(); tokenProvider = createTokenProvider(params); @@ -129,12 +130,12 @@ public class CloudFoundryClientCache { .build(); } - private TokenProvider createTokenProvider(Params params) { - CFCredentials creds = params.credentials; + private TokenProvider createTokenProvider(CFClientParams params) { + CFCredentials creds = params.getCredentials(); switch (creds.getType()) { case PASSWORD: return PasswordGrantTokenProvider.builder() - .username(params.username) + .username(params.getUsername()) .password(creds.getSecret()) .build(); case REFRESH_TOKEN: @@ -167,71 +168,12 @@ public class CloudFoundryClientCache { } } - 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 cache = new HashMap<>(); + private Map 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); + public synchronized CFClientProvider getOrCreate(CFClientParams params) { CFClientProvider client = cache.get(params); if (client==null) { clientCount++; @@ -243,7 +185,7 @@ public class CloudFoundryClientCache { return client; } - protected CFClientProvider create(Params params) { + protected CFClientProvider create(CFClientParams params) { return new CFClientProvider(params); } diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java index ab7cfb0a0..1310ec85e 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java @@ -151,7 +151,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { public DefaultClientRequestsV2(CloudFoundryClientCache clients, CFClientParams params, ClientTimeouts timeouts) { this.params = params; - CFClientProvider provider = clients.getOrCreate(params.getUsername(), params.getCredentials(), params.getHost(), params.skipSslValidation()); + CFClientProvider provider = clients.getOrCreate(params); this._client = provider.client; this._uaa = provider.uaaClient; this._tokenProvider = (AbstractUaaTokenProvider) provider.tokenProvider; @@ -203,7 +203,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { } } - @Override +// @Override public List getApplicationsWithBasicInfo() throws Exception { return ReactorUtils.get(operations_listApps()); } @@ -330,7 +330,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { * list. This is to avoid one 'bad apple' from spoiling the whole batch. (I.e if failing to fetch details for * some apps we can still return details for the others rather than throw an exception). */ - @Override +// @Override public Flux getApplicationDetails(List appsToLookUp) throws Exception { return Flux.fromIterable(appsToLookUp) .flatMap((CFApplication appSummary) -> { @@ -383,7 +383,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { }; } - @Override +// @Override public void stopApplication(String appName) throws Exception { ReactorUtils.get( stopApp(appName) @@ -399,7 +399,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public void restartApplication(String appName, CancelationToken cancelationToken) throws Exception { ReactorUtils.get(timeouts.getAppStartTimeout(), cancelationToken, restartApp(appName) @@ -414,7 +414,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public void logout() { _operations = null; _client = null; @@ -424,7 +424,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { return _client==null; } - @Override +// @Override public List getStacks() throws Exception { return ReactorUtils.get( log("operations.stacks().list()", @@ -436,7 +436,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public SshClientSupport getSshClientSupport() throws Exception { return new SshClientSupport() { @@ -492,7 +492,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { return client_createOperations(org); } - @Override +// @Override public List getSpaces() throws Exception { Object it = ReactorUtils.get(timeouts.getSpacesTimeout(), log("operations.organizations().list()", _operations.organizations() @@ -514,7 +514,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { return (List) it; } - @Override +// @Override public String getHealthCheck(UUID appGuid) throws Exception { //XXX CF V2: getHealthcheck (via operations API) // See: https://www.pivotaltracker.com/story/show/116462215 @@ -524,7 +524,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public void setHealthCheck(UUID guid, String hcType) throws Exception { //XXX CF V2: setHealthCheck (via operations API) // See: https://www.pivotaltracker.com/story/show/116462369 @@ -533,7 +533,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public List getDomains() throws Exception { //XXX CF V2: list domains using 'operations' api. return ReactorUtils.get(Duration.ofMinutes(2), @@ -561,7 +561,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public CFApplicationDetail getApplication(String appName) throws Exception { return ReactorUtils.get( getApplicationMono(appName) @@ -579,7 +579,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { } - @Override +// @Override public void deleteApplication(String appName) throws Exception { ReactorUtils.get( log("operations.applications().delete(name="+appName+")", @@ -592,7 +592,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public boolean applicationExists(String appName) throws Exception { return ReactorUtils.get( getApplicationMono(appName) @@ -615,7 +615,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { }); } - @Override +// @Override public void push(CFPushArguments params, CancelationToken cancelationToken) throws Exception { String appName = params.getAppName(); ReactorUtils.get(timeouts.getAppStartTimeout(), cancelationToken, @@ -1113,7 +1113,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { // deleteServiceMono(serviceName).get(); // } - @Override +// @Override public Mono deleteServiceAsync(String serviceName) { return getService(serviceName) .then(this::deleteServiceInstance); @@ -1150,7 +1150,7 @@ public class DefaultClientRequestsV2 implements ClientRequests { .map(this::dropObjectsFromMap); } - @Override +// @Override public Map getApplicationEnvironment(String appName) throws Exception { return ReactorUtils.get(getEnv(appName)); } @@ -1318,12 +1318,12 @@ public class DefaultClientRequestsV2 implements ClientRequests { ); } - @Override +// @Override public String getRefreshToken() { return _tokenProvider.getRefreshToken(); } - @Override +// @Override public Mono getUserName() { return log("uaa.getUsername", _uaa.getUsername() diff --git a/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java b/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java index 1f24e3595..9496f3a2d 100644 --- a/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java +++ b/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java @@ -17,9 +17,9 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; -import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetsFactory; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CfCliParamsProvider; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientTimeouts; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.CloudFoundryClientFactory; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.DefaultCloudFoundryClientFactoryV2; @@ -38,8 +38,8 @@ public class CFClientTest { CloudFoundryClientFactory clientFactory = DefaultCloudFoundryClientFactoryV2.INSTANCE; ClientTimeouts timeouts = ClientTimeouts.DEFAULT_TIMEOUTS; - CFTargetsFactory targets = new CFTargetsFactory(cliProvider, clientFactory, timeouts); - CFTarget target = targets.getTargets().get(0); + CFTargetCache targetCache = new CFTargetCache(cliProvider, clientFactory, timeouts); + CFTarget target = targetCache.getOrCreate().get(0); List buildPacks = target.getBuildpacks(); assertTrue(!buildPacks.isEmpty()); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java index 0cc883d1b..1dacfac44 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java @@ -20,7 +20,7 @@ import java.util.logging.Logger; import javax.inject.Provider; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; -import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetsFactory; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.ExceptionUtil; import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; @@ -29,13 +29,13 @@ import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; public abstract class AbstractCFHintsProvider implements Provider> { public static final String EMPTY_VALUE = ""; - protected final CFTargetsFactory targetsFactory; + protected final CFTargetCache targetCache; private static final Logger logger = Logger.getLogger(AbstractCFHintsProvider.class.getName()); - public AbstractCFHintsProvider(CFTargetsFactory targetsFactory) { - Assert.isNotNull(targetsFactory); - this.targetsFactory = targetsFactory; + public AbstractCFHintsProvider(CFTargetCache targetCache) { + Assert.isNotNull(targetCache); + this.targetCache = targetCache; } @Override @@ -45,19 +45,15 @@ public abstract class AbstractCFHintsProvider implements Provider targets = targetsFactory.getTargets(); - if (targets == null || targets.isEmpty()) { - hints.add(new BasicYValueHint(EMPTY_VALUE, targetsFactory.noTargetsMessage())); - } else { - Collection resolvedHints = getHints(targets); - hints.addAll(resolvedHints); - } + List targets = targetCache.getOrCreate(); + Collection resolvedHints = getHints(targets); + hints.addAll(resolvedHints); } catch (Throwable e) { logger.log(Level.SEVERE, e.getMessage(), e); // Don't throw exception as to allow the CA to be displayed to the // user. if (e instanceof IOException || ExceptionUtil.getDeepestCause(e) instanceof IOException) { - hints.add(new BasicYValueHint(EMPTY_VALUE, "Connection failure. " + targetsFactory.noTargetsMessage())); + hints.add(new BasicYValueHint(EMPTY_VALUE, "Connection failure. " + e.getMessage())); } else { hints.add(new BasicYValueHint(EMPTY_VALUE, "Unable to fetch Cloud Foundry proposals due to: " + e.getMessage())); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFBuildpacksProvider.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFBuildpacksProvider.java index 88aa4bb89..4edb64408 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFBuildpacksProvider.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFBuildpacksProvider.java @@ -16,14 +16,14 @@ import java.util.List; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; -import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetsFactory; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; public class ManifestYamlCFBuildpacksProvider extends AbstractCFHintsProvider { - public ManifestYamlCFBuildpacksProvider(CFTargetsFactory targetsFactory) { - super(targetsFactory); + public ManifestYamlCFBuildpacksProvider(CFTargetCache cache) { + super(cache); } @Override @@ -45,7 +45,7 @@ public class ManifestYamlCFBuildpacksProvider extends AbstractCFHintsProvider { } if (hints.isEmpty()) { - hints.add(new BasicYValueHint(EMPTY_VALUE, "No buildpacks found. " + targetsFactory.noTargetsMessage())); + hints.add(new BasicYValueHint(EMPTY_VALUE, "No Cloud Foundry buildpacks found.")); } return hints; } diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFServicesProvider.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFServicesProvider.java index bdcd5f58e..2ea9593e7 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFServicesProvider.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFServicesProvider.java @@ -16,14 +16,14 @@ import java.util.List; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; -import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetsFactory; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; public class ManifestYamlCFServicesProvider extends AbstractCFHintsProvider { - public ManifestYamlCFServicesProvider(CFTargetsFactory targetsFactory) { - super(targetsFactory); + public ManifestYamlCFServicesProvider(CFTargetCache cache) { + super(cache); } @Override @@ -31,7 +31,7 @@ public class ManifestYamlCFServicesProvider extends AbstractCFHintsProvider { List hints = new ArrayList<>(); for (CFTarget cfTarget : targets) { - List services = cfTarget.getClientRequests().getServices(); + List services = cfTarget.getServices(); if (services != null) { for (CFServiceInstance service : services) { String name = service.getName(); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java index 64aec10c3..04d565467 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java @@ -18,9 +18,9 @@ import javax.inject.Provider; import org.eclipse.lsp4j.CompletionOptions; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.TextDocumentSyncKind; -import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetsFactory; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CfCliParamsProvider; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.ClientTimeouts; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.CloudFoundryClientFactory; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.DefaultCloudFoundryClientFactoryV2; @@ -50,7 +50,7 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { private Yaml yaml = new Yaml(); private YamlSchema schema; - private CFTargetsFactory cfTargetsFactory; + private CFTargetCache cfTargetCache; private static final ClientTimeouts VSCODE_CF_CLIENT_TIMEOUTS = new ClientTimeouts() { @@ -103,21 +103,21 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { documents.onHover(hoverEngine ::getHover); } - private CFTargetsFactory getCFTargetsFactory() { - if (cfTargetsFactory == null) { + private CFTargetCache getCfTargetCache() { + if (cfTargetCache == null) { ClientParamsProvider paramsProvider = new CfCliParamsProvider(); CloudFoundryClientFactory clientFactory = DefaultCloudFoundryClientFactoryV2.INSTANCE; - cfTargetsFactory = new CFTargetsFactory(paramsProvider, clientFactory, VSCODE_CF_CLIENT_TIMEOUTS); + cfTargetCache = new CFTargetCache(paramsProvider, clientFactory, VSCODE_CF_CLIENT_TIMEOUTS); } - return cfTargetsFactory; + return cfTargetCache; } private Provider> getBuildpacksProvider() { - return new ManifestYamlCFBuildpacksProvider(getCFTargetsFactory()); + return new ManifestYamlCFBuildpacksProvider(getCfTargetCache()); } private Provider> getServicesProvider() { - return new ManifestYamlCFServicesProvider(getCFTargetsFactory()); + return new ManifestYamlCFServicesProvider(getCfTargetCache()); } @Override